home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume3 / sm-smtp < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  62.5 KB

  1. Path: xanth!mcnc!gatech!bloom-beacon!husc6!necntc!ncoast!allbery
  2. From: jv@mh.nl.UUCP (Johan Vromans)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i019: Sendmail replacement for smail sites
  5. Keywords: mail sendmail smail smtp tcp-ip
  6. Message-ID: <1863@mhres.mh.nl>
  7. Date: 16 May 88 15:24:17 GMT
  8. Sender: allbery@ncoast.UUCP
  9. Reply-To: jv@mh.nl.UUCP (Johan Vromans)
  10. Organization: Multihouse NV, the Netherlands
  11. Lines: 2701
  12. Approved: allbery@ncoast.UUCP
  13.  
  14. comp.sources.misc: Volume 3, Issue 19
  15. Submitted-By: "Johan Vromans" <jv@mh.nl.UUCP>
  16. Archive-Name: sm-smtp
  17.  
  18. Lots of people asked me for this, so here it is ...
  19.  
  20. This is a merger of Ian's standalone talker and MIT's talker.
  21. Peter Honeyman hacked on it to make it work correctly on the Arpanet.
  22.  
  23. Adapted by Johan Vromans <jv@mh.nl>, May 1988
  24.  
  25.  - simplified code
  26.  
  27.  - adapted to System V (Most notably: HP-UX)
  28.  
  29.  - added better host/domain name handling & setup
  30.  
  31.  - added time-routine (from smail)
  32.  
  33.  - added "config.h" for local settings, and moved common includes and
  34.    portability code to "smtp.h"
  35.  
  36.  - produces a "smtpd" to be used under inetd, "sa-smtpd" (standalone) and
  37.    "smtp" interface program.
  38.  
  39. #---------------- cut here ----------------
  40. #! /bin/sh
  41. # This is a shell archive, meaning:
  42. # 1. Remove everything above the #! /bin/sh line.
  43. # 2. Save the resulting text in a file.
  44. # 3. Execute the file with /bin/sh (not csh) to create:
  45. #    Makefile
  46. #    README
  47. #    cmds.h
  48. #    config.h
  49. #    converse.c
  50. #    dconverse.c
  51. #    misc.c
  52. #    miscerrs.h
  53. #    mx.c
  54. #    netio.c
  55. #    smtp.8
  56. #    smtp.c
  57. #    smtp.h
  58. #    smtpd.c
  59. #    sysexits.h
  60. #    syslog.h
  61. #    MANIFEST
  62. # This archive created: Mon May 16 17:16:19 1988
  63. export PATH; PATH=/bin:/usr/bin:$PATH
  64. echo shar: "extracting 'Makefile'" '(800 characters)'
  65. if test -f 'Makefile'
  66. then
  67.     echo shar: "will not over-write existing file 'Makefile'"
  68. else
  69. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  70. X#!/bin/make
  71. X
  72. XCFLAGS    = -O
  73. XLIBS    = -lBSD -lbsdipc -lsyslog    # HP-UX
  74. X#LIBS    =                # BSD
  75. X
  76. Xall:    smtp smtpd
  77. X
  78. XSTD    = netio.o misc.o
  79. X
  80. Xsmtp:    smtp.o converse.o $(STD)
  81. X    $(CC) $(CFLAGS) -o smtp smtp.o converse.o $(STD) $(LIBS)
  82. X
  83. Xsmtpd:    smtpd.o dconverse.o $(STD)
  84. X    $(CC) $(CFLAGS) -o smtpd smtpd.o dconverse.o $(STD) $(LIBS)
  85. X
  86. Xsa-smtpd:    sa-smtpd.o dconverse.o $(STD)
  87. X    $(CC) $(CFLAGS) -o sa-smtpd sa-smtpd.o dconverse.o $(STD) $(LIBS)
  88. X
  89. Xsmptd.o sa-smtpd.o smtp.o $(STD) converse.o: smtp.h
  90. X
  91. Xsmtp.h:    config.h miscerrs.h
  92. X    -touch smtp.h
  93. X
  94. Xsmtpd.o:    smtpd.c
  95. X    $(CC) -c $(CFLAGS) -DINETD smtpd.c
  96. X
  97. Xsa-smtpd.o:    smtpd.c
  98. X    $(CC) -c $(CFLAGS) -UINETD smtpd.c
  99. X    mv smtpd.o sa-smtpd.o
  100. X
  101. Xclean:
  102. X    rm -f smtp smtpd sa-smtpd *.o
  103. X
  104. Xlint:
  105. X    lint smtp.c netio.c converse.c
  106. X    lint smtpd.c netio.c dconverse.c
  107. X    lint -DINETD smtpd.c netio.c dconverse.c
  108. X
  109. SHAR_EOF
  110. if test 800 -ne "`wc -c < 'Makefile'`"
  111. then
  112.     echo shar: "error transmitting 'Makefile'" '(should have been 800 characters)'
  113. fi
  114. fi
  115. echo shar: "extracting 'README'" '(2322 characters)'
  116. if test -f 'README'
  117. then
  118.     echo shar: "will not over-write existing file 'README'"
  119. else
  120. sed 's/^X//' << \SHAR_EOF > 'README'
  121. XThis is a merger of Ian's standalone talker and MIT's talker.
  122. XPeter Honeyman hacked on it to make it work correctly on the Arpanet.
  123. X
  124. XAdapted by Johan Vromans <jv@mh.nl>, May 1988
  125. X
  126. X - simplified code
  127. X
  128. X - adapted to System V (Most notably: HP-UX)
  129. X
  130. X - added better host/domain name handling & setup
  131. X
  132. X - added time-routine (from smail)
  133. X
  134. X - added "config.h" for local settings, and moved common includes and
  135. X   portability code to "smtp.h"
  136. X
  137. X - produces a "smtpd" to be used under inetd, "sa-smtpd" (standalone) and
  138. X   "smtp" interface program.
  139. X
  140. XDisclaimers: it works for me. I didn't test "sa-smtpd", nor tried it under
  141. XBerkeley Unix. However, the code originated from BSD, and I tried to keep
  142. Xsystem dependent things intact.
  143. XI did not look at the "mx" program which is also included.
  144. X
  145. XHow I use it
  146. X------------
  147. XI use a mail system based on smail 2.5.
  148. X
  149. XMy user agents can be Elm, mail or mailx, and pass the message to smail for
  150. Xaliasing and routing. Smail hands the message to either a localmail program
  151. X(for local delivery: user mailboxes, programs or files) or a remotemail
  152. Xprogram (for remote delivery: uucp or smtp).
  153. X
  154. XIn the routing database, all hosts I can connect to are considered
  155. X"UUCP"-hosts, and delivery is passed to a shell script. In this script,
  156. Xhosts are looked-up in the file /etc/hosts.smtp (with the names of TCP/IP
  157. Xhosts which speak smtp) and - if found - delivery is passed to the smtp
  158. Xprogram. 
  159. X
  160. XOtherwise delivery is passed to uux as usual.
  161. X
  162. XOn the input side, smtp mail is caught by the smtpd program, and passed to
  163. Xsmail for further processing.
  164. X
  165. XWhy I don't use sendmail
  166. X------------------------
  167. XUsing sendmail has a few drawbacks:
  168. X
  169. X - it is hard to configure and difficult to maintain
  170. X
  171. X - lots of the functionality of sendmail is also in smail. Who is aliasing,
  172. X   who is routing, who is bouncing?
  173. X
  174. X - I cannot prevent sendmail from rewriting message headers
  175. X
  176. X - when something goes wrong, sendmail will try to do sensible things
  177. X   which bypass the rest of the mail system
  178. X
  179. XSmail does everything I want, except for the SMTP delivery. Well - the
  180. Xprograms included do just that.
  181. X
  182. XAnd last but not least: it is more easy to maintain a few small, well
  183. Xdocumented and easy to understand programs than one big hard to understand/
  184. Xconfigure/maintain program. 
  185. X
  186. XMay 1988, Johan Vromans, Multihouse Research
  187. SHAR_EOF
  188. if test 2322 -ne "`wc -c < 'README'`"
  189. then
  190.     echo shar: "error transmitting 'README'" '(should have been 2322 characters)'
  191. fi
  192. fi
  193. echo shar: "extracting 'cmds.h'" '(1024 characters)'
  194. if test -f 'cmds.h'
  195. then
  196.     echo shar: "will not over-write existing file 'cmds.h'"
  197. else
  198. sed 's/^X//' << \SHAR_EOF > 'cmds.h'
  199. X#ifndef lint
  200. Xstatic char *cmds_sccsid = "@(#)cmds.h    1.5 87/04/06";
  201. X#endif lint
  202. X/* cmds.h */
  203. X
  204. X/*  Copyright 1984 by the Massachusetts Institute of Technology  */
  205. X/*  See permission and disclaimer notice in file "notice.h"  */
  206. X
  207. X/* EMACS_MODES: c !fill */
  208. X
  209. X/*
  210. X * smtp command strings and associated codes.  Note that the command code
  211. X * MUST be equal to the index of the command in the table.
  212. X */
  213. X
  214. X
  215. Xstruct    cmdtab    {
  216. X    char    *c_name;        /* command name */
  217. X    int    c_len;            /* command length */
  218. X} cmdtab[] = {
  219. X#define    NONE        0        /* no such command */
  220. X    { "", 0, },
  221. X#define    HELO        1
  222. X    { "HELO", 4, },
  223. X#define    MAIL        2
  224. X    { "MAIL FROM:", 10 },
  225. X#define    RCPT        3
  226. X    { "RCPT TO:", 8, },
  227. X#define    DATA        4
  228. X    { "DATA", 4, },
  229. X#define    QUIT        5
  230. X    { "QUIT", 4, },
  231. X#define    RSET        6
  232. X    { "RSET", 4, },
  233. X#define    NOOP        7
  234. X    { "NOOP", 4, },
  235. X#define VRFY        8
  236. X    { "VRFY", 4, },
  237. X/* sendmail compatibility */
  238. X#define ONEX        9
  239. X    { "ONEX", 4, },
  240. X#define VERB        10
  241. X    { "VERB", 4, },
  242. X
  243. X    { 0, 0, }            /* end of table marker */
  244. X};
  245. X#define toupper(c)    (islower(c) ? ((c) - ('a' - 'A')) : (c))
  246. SHAR_EOF
  247. if test 1024 -ne "`wc -c < 'cmds.h'`"
  248. then
  249.     echo shar: "error transmitting 'cmds.h'" '(should have been 1024 characters)'
  250. fi
  251. fi
  252. echo shar: "extracting 'config.h'" '(1280 characters)'
  253. if test -f 'config.h'
  254. then
  255.     echo shar: "will not over-write existing file 'config.h'"
  256. else
  257. sed 's/^X//' << \SHAR_EOF > 'config.h'
  258. X/* config.h for smtp package */
  259. X
  260. X/*
  261. X * define either BSD or SYSV.
  262. X */
  263. X#define SYSV            /* SystemV with TCP/IP */
  264. X/* # define BSD            /* Berkeley 4.[23] */
  265. X
  266. X/*
  267. X * If set, HOSTDOMAIN overrides HOSTNAME and MYDOM.
  268. X */
  269. X/* #define HOSTDOMAIN    "mhres.mh.nl" */
  270. X
  271. X/*
  272. X * If not set, HOSTNAME will be fetched using uname (SYSV) or gethostname (BSD)
  273. X */
  274. X/* #define HOSTNAME    "mhres" */
  275. X
  276. X/*
  277. X * If set, MYDOM will be appended to the host name.
  278. X */
  279. X#define MYDOM        ".mh.nl"
  280. X
  281. X/*
  282. X * Define server to use. Defaults to "smtp".
  283. X */
  284. X/* #define SERVNAME    "tsmtp" */
  285. X
  286. X/*
  287. X * Define SYSLOG when the syslog rotuine can be used. For SYSV, it will
  288. X * use a PD syslog package.
  289. X */
  290. X#define SYSLOG
  291. X
  292. X/*
  293. X * Define this if you want a log of mail transactions. See the code in
  294. X * smtpd.c.
  295. X */
  296. X#define SIMPLELOG
  297. X
  298. X/*
  299. X * The mailer used to send the mail.
  300. X */
  301. X#define MAILER    "/bin/smail"
  302. X
  303. X/*
  304. X * Define HOOTING for printout of transaction (needed for "Transaction
  305. X * of session")
  306. X * Used by "netio" in "smtp"
  307. X */
  308. X#define HOOTING
  309. X
  310. X/*
  311. X * Define NOSYSEXITS iy you don't have <sysexits.h> (or "sysexits.h" on SYSV.
  312. X */
  313. X
  314. X/* define NOSYSEXITS */
  315. X
  316. X/*
  317. X * Define this if your signal(2) takes a void function as its second arg.
  318. X * Otherwise leave it empty
  319. X */
  320. X
  321. X/* define TYPESIG    ((void)(*)())    */
  322. X#ifndef TYPESIG
  323. X# define TYPESIG
  324. X#endif
  325. X
  326. SHAR_EOF
  327. if test 1280 -ne "`wc -c < 'config.h'`"
  328. then
  329.     echo shar: "error transmitting 'config.h'" '(should have been 1280 characters)'
  330. fi
  331. fi
  332. echo shar: "extracting 'converse.c'" '(4950 characters)'
  333. if test -f 'converse.c'
  334. then
  335.     echo shar: "will not over-write existing file 'converse.c'"
  336. else
  337. sed 's/^X//' << \SHAR_EOF > 'converse.c'
  338. X/*
  339. X * Do the necessary commands for a smtp transfer.  Start by waiting for the
  340. X * connection to open, then send HELO, MAIL, RCPT, and DATA.  Check the
  341. X * reply codes and give up if needed.
  342. X * 
  343. X * This code modified from the MIT UNIX TCP implementation:
  344. X * Copyright 1984 Massachusetts Institute of Technology
  345. X * 
  346. X * Permission to use, copy, modify, and distribute this file
  347. X * for any purpose and without fee is hereby granted, provided
  348. X * that this copyright and permission notice appear on all copies
  349. X * and supporting documentation, the name of M.I.T. not be used
  350. X * in advertising or publicity pertaining to distribution of the
  351. X * program without specific prior permission, and notice be given
  352. X * in supporting documentation that copying and distribution is
  353. X * by permission of M.I.T.  M.I.T. makes no representations about
  354. X * the suitability of this software for any purpose.  It is provided
  355. X * "as is" without express or implied warranty.
  356. X */
  357. X
  358. X#include "smtp.h"
  359. X#include <signal.h>
  360. X
  361. X#define    MAXTIME        (60 * 5)        /* way too long - die */
  362. X
  363. Xint success, termcode;
  364. X
  365. Xint gethostname();
  366. Xextern int death();
  367. Xchar *strcat(), *strcpy();
  368. Xextern char hostname[], hostdomain[];
  369. X
  370. Xconverse(from, rcpt, sfi, sfo, mlfd)
  371. Xchar    *from;                /* from address */
  372. Xchar    *rcpt;                /* to address */
  373. XFILE    *sfi;                /* smtp input */
  374. XFILE    *sfo;                /* smtp output */
  375. XFILE    *mlfd;                /* mail file descriptor */
  376. X{
  377. X    extern expect();
  378. X    extern char *sendhost;
  379. X    char buf[MAXSTR];
  380. X    char host[64];
  381. X
  382. X    (void) signal(SIGALRM, TYPESIG death);
  383. X    (void) alarm(MAXTIME);        /* make sure we eventually go away */
  384. X
  385. X    expect(220, sfi, sfo);            /* expect a service ready msg */
  386. X/*    (void) gethostname(host, sizeof host); */
  387. X
  388. X    if (sendhost == NULL)
  389. X        (void) sprintf(buf, "HELO %s.%s\n", hostdomain);
  390. X    else
  391. X        (void) sprintf(buf, "HELO %s\n", sendhost);
  392. X    tputs(buf, sfo);
  393. X    expect(250, sfi, sfo);            /* expect an OK */
  394. X
  395. X    (void) strcpy(buf, "MAIL FROM:<");
  396. X    (void) strcat(buf, from);
  397. X    (void) strcat(buf, ">\n");
  398. X    tputs(buf, sfo);
  399. X    expect(250, sfi, sfo);            /* expect OK */
  400. X
  401. X    (void) strcpy(buf, "RCPT TO:<");
  402. X    (void) strcat(buf, rcpt);
  403. X    (void) strcat(buf, ">\n");
  404. X    tputs(buf, sfo);
  405. X    expect(250, sfi, sfo);            /* expect OK */
  406. X
  407. X    tputs("DATA\n", sfo);
  408. X    expect(354, sfi, sfo);
  409. X    do_data(mlfd, sfo);
  410. X    expect(250, sfi, sfo);            /* hope data is OK */
  411. X    success = TRUE;
  412. X
  413. X    tputs("QUIT\n", sfo);
  414. X    /*expect(221, sfi, sfo);*/    /* who cares? */
  415. X}
  416. X
  417. X
  418. X/*
  419. X * Send the data from the specified mail file out on the current smtp
  420. X * connection.  Do the appropriate netascii conversion and starting '.'
  421. X * padding.  Send the <CRLF>.<CRLF> at completion.
  422. X */
  423. Xdo_data(fd, sfo)
  424. Xregister FILE    *fd;            /* mail file descriptor */
  425. XFILE *sfo;                /* smtp files */
  426. X{
  427. X    register int c;        /* current character */
  428. X    int nlseen = FALSE;        /* newline */
  429. X    extern int debug;
  430. X
  431. X    if (debug)
  432. X        (void) printf("in do_data\n");
  433. X    while ((c = getc(fd)) != EOF) {
  434. X        if (nlseen) {
  435. X            nlseen = FALSE;
  436. X            if (c == '.')
  437. X                (void) putc('.', sfo);
  438. X        }
  439. X        if (c == '\n') {
  440. X            (void) putc('\r', sfo);
  441. X            nlseen = TRUE;
  442. X        }
  443. X        (void) putc(c, sfo);
  444. X#ifdef what_the_fuck_is_all_this_about
  445. X        if (c == '\r')
  446. X            (void) putc('\0', sfo);
  447. X#endif
  448. X    }
  449. X    if (!nlseen) {
  450. X        (void) putc('\r', sfo);
  451. X        (void) putc('\n', sfo);
  452. X    }
  453. X#ifdef this_is_bullshit_too
  454. X    (void) putc('\n', sfo);    /* TODO: why is this line needed? */
  455. X#endif
  456. X    (void) putc('.', sfo);
  457. X    (void) putc('\r', sfo);
  458. X    (void) putc('\n', sfo);
  459. X    (void) fflush(sfo);
  460. X    if (ferror(sfo)) {
  461. X        perror("write error in smtp");
  462. X        bomb(E_IOERR);
  463. X    }
  464. X    if (debug)
  465. X        (void) printf("leaving do_data\n");
  466. X}
  467. X
  468. X
  469. X/*
  470. X * Expect a reply message with the specified code.  If the specified code
  471. X * is received return TRUE; otherwise print the error message out on the
  472. X * standard output and give up.  Note that the reply can be a multiline
  473. X * message.
  474. X */
  475. Xexpect(code, sfi, sfo)
  476. Xint    code;
  477. XFILE    *sfi, *sfo;
  478. X{
  479. X    int retcd;
  480. X    char cmdbuf[MAXSTR], termbuf[MAXSTR];
  481. X    extern int debug;
  482. X
  483. X    if (debug)
  484. X        (void) fprintf(stderr, "expect %d ", code);
  485. X    for (;;) {            /* get whole reply */
  486. X        if (tgets(cmdbuf, sizeof cmdbuf, sfi) > 0) {    /* get input line */
  487. X            if (cmdbuf[3] == '-') /* continuation line? */
  488. X                continue;
  489. X                        /* no, last line */
  490. X            if (sscanf(cmdbuf, "%d", &retcd) !=1 ){
  491. X                (void) fprintf(stderr,
  492. X                    "non-numeric command reply!\n");
  493. X                bomb(E_IOERR);
  494. X            }
  495. X            if (retcd == code) {
  496. X                if (debug)
  497. X                    (void) fprintf(stderr," got it\n");
  498. X                return;
  499. X            }
  500. X            else {
  501. X                if (debug)
  502. X                    (void) fprintf(stderr,
  503. X                        " FAIL (got %d)\n", retcd);
  504. X                /* return the error line */
  505. X                (void) strcpy(termbuf, cmdbuf);
  506. X                tputs ("QUIT\n", sfo);
  507. X                break;
  508. X            }
  509. X        } 
  510. X        else if (success)
  511. X            (void) strcpy(termbuf, "250 OK\n");
  512. X        else {
  513. X            (void) perror("smtp");
  514. X            bomb(451);
  515. X        }
  516. X    }
  517. X    termcode = !success;            /* error return */
  518. X    if (debug)
  519. X        (void) fprintf(stderr, " FALLOUT\n");
  520. X    bomb(retcd);        /* map smtp errors to mailsys errors */
  521. X}
  522. X
  523. X/* Maximum time to live elapsed.  Die right now. */
  524. Xdeath()
  525. X{
  526. X    (void) fprintf(stderr, "Max transfer length timeout.\n");
  527. X    (void) exit(1);
  528. X}
  529. SHAR_EOF
  530. if test 4950 -ne "`wc -c < 'converse.c'`"
  531. then
  532.     echo shar: "error transmitting 'converse.c'" '(should have been 4950 characters)'
  533. fi
  534. fi
  535. echo shar: "extracting 'dconverse.c'" '(12608 characters)'
  536. if test -f 'dconverse.c'
  537. then
  538.     echo shar: "will not over-write existing file 'dconverse.c'"
  539. else
  540. sed 's/^X//' << \SHAR_EOF > 'dconverse.c'
  541. X#ifndef lint
  542. Xstatic char *sccsid = "@(#)converse.c    1.8 87/05/14";
  543. X#endif lint
  544. X/*  Copyright 1984 Massachusetts Institute of Technology
  545. X
  546. XPermission to use, copy, modify, and distribute this program
  547. Xfor any purpose and without fee is hereby granted, provided
  548. Xthat this copyright and permission notice appear on all copies
  549. Xand supporting documentation, the name of M.I.T. not be used
  550. Xin advertising or publicity pertaining to distribution of the
  551. Xprogram without specific prior permission, and notice be given
  552. Xin supporting documentation that copying and distribution is
  553. Xby permission of M.I.T.  M.I.T. makes no representations about
  554. Xthe suitability of this software for any purpose.  It is pro-
  555. Xvided "as is" without express or implied warranty.        */
  556. X
  557. X/*
  558. X * smtpd - World's most trivial SMTP server.  Only accepts the MAIL, FROM,
  559. X * RCPT, and DATA commands.  Generates a date file for the mail
  560. X * daemon and kicks the mail daemon off.
  561. X */
  562. X
  563. X#include "smtp.h"
  564. X
  565. X#ifdef BSD
  566. X#include <sgtty.h>
  567. X#endif
  568. X/* #include <ioctl.h> */
  569. X#include <signal.h>
  570. X#include <sys/uio.h>
  571. X#include <sys/socket.h>
  572. X#include <netinet/in.h>
  573. X
  574. X#include "cmds.h"
  575. X
  576. X/* tunable constants */
  577. X
  578. X#define SECONDS        1
  579. X#define MINUTES        60
  580. X#define HOURS        (60 * MINUTES)
  581. X
  582. X#define    SHORTTIME    (5 * MINUTES)    /* enough time for easy stuff */
  583. X#define    LONGTIME    (2 * HOURS)    /* max time, DATA to `.' */
  584. X
  585. X#define    DATAMODE    0660        /* mode for data file */
  586. X
  587. X#ifdef MAILER
  588. Xchar *sigmaild = MAILER;
  589. X#else
  590. Xchar *sigmaild = "/bin/rmail";
  591. X#endif
  592. X
  593. Xtypedef long in_name;            /* internet host address */
  594. X
  595. Xint    buflen;                /* size of string in cmd buffer */
  596. X
  597. Xstatic char rcptlist[MAXSTR];        /* recipient list */
  598. Xstatic char *rcptlast;            /* end of rcptlist */
  599. X
  600. XFILE    *datafd;            /* data file descriptor */
  601. X
  602. Xchar    dataname[NAMSIZ];        /* data file name */
  603. X
  604. Xtypedef int event;
  605. X
  606. Xextern int death();
  607. Xextern int alarmtr();
  608. X
  609. Xextern char *strcpy();
  610. Xextern char *index();
  611. Xextern char *rindex();
  612. Xextern char *strcpy(), *strcat();
  613. X
  614. Xextern char hostdomain[];
  615. Xextern char hostname[];
  616. Xextern char arpanows[];
  617. X
  618. X#ifdef SIMPLELOG
  619. X#include <sys/file.h>
  620. Xstatic char mailfrom[MAXSTR], rcptto[MAXSTR];
  621. X#endif
  622. X
  623. X/*
  624. X * This is the routine which processes incoming smtp commands from the
  625. X * user.  It goes to sleep awaiting network input.  When a complete
  626. X * command is received, the tcp receiver task awakens us to process it.
  627. X * Currently only the commands listed in the command table are accepted.
  628. X * This routine never returns.
  629. X */
  630. X/* ARGSUSED from */
  631. Xconverse(fi, fo, from)
  632. XFILE *fi, *fo;
  633. Xstruct sockaddr_in *from;
  634. X{
  635. X    char greeting[MAXSTR];
  636. X
  637. X    (void) chdir("/tmp");        /* put temp files somewhere sensible */
  638. X    (void) signal(SIGALRM, TYPESIG alarmtr);
  639. X    (void) alarm(SHORTTIME);        /* make sure we eventually go away */
  640. X    setdates ();
  641. X    (void) sprintf(greeting, "220 %s SMTP server ready at %s\n",
  642. X        hostdomain, arpanows);
  643. X    (void) tputs(greeting, fo);
  644. X    do_helo(fi, fo);        /* wait for the hello */
  645. X    for (;;) {            /* until QUIT */
  646. X        do_mail(fi, fo);    /* wait for the mail command */
  647. X        while (do_rcpt(fi, fo))    /* do all the recipients */
  648. X            ;
  649. X        (void) alarm(LONGTIME);
  650. X        do_data(fi, fo);    /* do the data */
  651. X    }
  652. X}
  653. X
  654. X/*
  655. X * Wait for the user to send the HELO command.  Punt out if he sends
  656. X * QUIT or RSET.
  657. X */
  658. Xdo_helo(fi, fo)
  659. XFILE *fi, *fo;
  660. X{
  661. X    char    cmdbuf[MAXSTR];
  662. X    char    greeting[MAXSTR];
  663. X
  664. X    for (;;) {        /* until HELO, QUIT, or RSET */
  665. X        buflen = tgets(cmdbuf, sizeof cmdbuf, fi);    /* wait for command */
  666. X        switch (cmdparse(cmdbuf, buflen)) {
  667. X        case QUIT:
  668. X        case RSET:
  669. X            quit(fi, fo);
  670. X        case NOOP:
  671. X            (void) tputs("250 OK\n", fo);
  672. X            continue;
  673. X        case HELO:
  674. X            (void) sprintf(greeting, "250 %s Pleased to meet you\n", hostname);
  675. X            (void) tputs(greeting, fo);
  676. X            return;
  677. X        case NONE:
  678. X            bitch(cmdbuf, fo);
  679. X            continue;
  680. X        default:
  681. X            (void) tputs("503 Expecting HELO\n", fo);
  682. X            continue;
  683. X        }
  684. X    }
  685. X}
  686. X
  687. X/*
  688. X * Wait for the user to send the MAIL command.  Punt out if he sends
  689. X * QUIT or RSET.
  690. X */
  691. Xdo_mail(fi, fo)
  692. XFILE *fi, *fo;
  693. X{
  694. X    char    cmdbuf[MAXSTR];
  695. X
  696. X    for (;;) {        /* until MAIL, QUIT, or RSET */
  697. X        buflen = tgets(cmdbuf, sizeof cmdbuf, fi);    /* wait for command */
  698. X        switch (cmdparse(cmdbuf, buflen)) {
  699. X        case QUIT:
  700. X        case RSET:
  701. X            quit(fi, fo);
  702. X        case NOOP:
  703. X            (void) tputs("250 OK\n", fo);
  704. X            continue;
  705. X        case MAIL:
  706. X#ifdef SIMPLELOG
  707. X            strcpy(mailfrom, cmdbuf);
  708. X#endif
  709. X            (void) tputs("250 OK\n", fo);
  710. X            return;
  711. X        case NONE:
  712. X            bitch(cmdbuf, fo);
  713. X            continue;
  714. X        default:
  715. X            (void) tputs("503 Expecting MAIL\n", fo);
  716. X            continue;
  717. X        }
  718. X    }
  719. X}
  720. X
  721. X/*
  722. X * Wait for the user to send the RCPT command.  Punt out if he sends
  723. X * QUIT or RSET.  Returns TRUE if a RCPT command was received, FALSE
  724. X * if a DATA command was received.
  725. X */
  726. Xdo_rcpt(fi, fo)
  727. XFILE *fi, *fo;
  728. X{
  729. X    char    cmdbuf[MAXSTR];
  730. X
  731. X    for (;;) {        /* until RCPT, DATA, QUIT, or RSET */
  732. X        buflen = tgets(cmdbuf, sizeof cmdbuf, fi);    /* wait for command */
  733. X        switch (cmdparse(cmdbuf, buflen)) {
  734. X        case QUIT:
  735. X        case RSET:
  736. X            quit(fi, fo);
  737. X        case NOOP:
  738. X            (void) tputs("250 OK\n", fo);
  739. X            continue;
  740. X        case RCPT:
  741. X#ifdef SIMPLELOG
  742. X            strcat(rcptto, cmdbuf);
  743. X#endif
  744. X            if (!parse_rcpt(cmdbuf, buflen)) {
  745. X                (void) tputs("501 Syntax error in recipient name\n", fo);
  746. X                continue;
  747. X            }
  748. X            (void) tputs("250 OK\n", fo);
  749. X            return(TRUE);
  750. X        case DATA:
  751. X            if (*rcptlist == 0) {
  752. X                (void) tputs("503 Expecting RCPT\n", fo);
  753. X                continue;
  754. X            }
  755. X            if (!init_xfr()) {    /* set up data file */
  756. X                (void) tputs("451 Can't initialize transfer\n", fo);
  757. X                death(E_CANTOPEN);
  758. X            }
  759. X            (void) tputs("354 Start mail input; end with <CRLF>.<CRLF>\n", fo);
  760. X            return(FALSE);
  761. X        case NONE:
  762. X            bitch(cmdbuf, fo);
  763. X            continue;
  764. X        default:
  765. X            (void) tputs("503 Expecting RCPT or DATA\n", fo);
  766. X            continue;
  767. X        }
  768. X    }
  769. X}
  770. X
  771. Xdo_data(fi, fo)
  772. XFILE *fi, *fo;
  773. X{
  774. X    char cmd[MAXSTR];
  775. X    register char *buf = cmd;
  776. X    int sysret;
  777. X
  778. X    setdates ();
  779. X    fprintf (datafd, "Received: by %s with SMTP; %s\n",
  780. X        hostdomain, arpanows);
  781. X    for (;;) {
  782. X        if (tgets(buf, sizeof cmd, fi) < 0)
  783. X            death(E_IOERR);
  784. X        if (*buf == '.') {
  785. X            buf++;    /* hidden dot */
  786. X            if (*buf == '\n')
  787. X                break;
  788. X        }
  789. X        (void) fputs(buf, datafd);
  790. X    }
  791. X
  792. X    (void) fclose(datafd);
  793. X
  794. X    /* run mailer with rcptlist as args and message as input */
  795. X    /* TODO: check system status to see if OK */
  796. X    (void) sprintf(cmd, "%s %s <%s", sigmaild, rcptlist, dataname);
  797. X    sysret = system(cmd);
  798. X    if (sysret == 0)
  799. X        (void) tputs("250 OK\n", fo);
  800. X    else
  801. X        (void) tputs("554 Transaction failed\n", fo);
  802. X
  803. X#ifdef SIMPLELOG
  804. X    simplelog(abs(sysret));
  805. X#endif
  806. X
  807. X    /* shouldn't leave it around, but ... */
  808. X    if (sysret == 0)
  809. X        (void) unlink(dataname);    /* remove temporaries */
  810. X
  811. X    *dataname = *rcptlist = *rcptto = 0;
  812. X    rcptlast = 0;
  813. X}
  814. X
  815. X/*
  816. X * Create the data file for the transfer.  Get unique
  817. X * names and create the files.
  818. X */
  819. Xinit_xfr()
  820. X{
  821. X    int    dfd;            /* file desc. for data file */
  822. X
  823. X    (void) tmpnam(dataname);
  824. X    
  825. X    if ((dfd = creat(dataname, DATAMODE)) < 0)
  826. X        return FALSE;
  827. X    datafd = fdopen(dfd, "w");    /* make stdio descriptor */
  828. X    if (datafd == NULL)
  829. X        return FALSE;
  830. X
  831. X    
  832. X    return TRUE;
  833. X}
  834. X
  835. X/*
  836. X * Give up on the transfer.  Unlink the data file (if any),
  837. X * close the tcp connection, and exit.
  838. X */
  839. Xquit(fi, fo)
  840. XFILE *fi, *fo;
  841. X{
  842. X    char greeting[MAXSTR];
  843. X
  844. X    (void) sprintf(greeting, "221 %s Terminating\n", hostname);
  845. X    (void) tputs(greeting, fo);
  846. X    (void) fclose(fi);
  847. X    (void) fclose(fo);
  848. X    exit(0);
  849. X}
  850. X
  851. X/*
  852. X * Parse the command part off the specified buffer.  Return the index
  853. X * of the command in the command table(or 0 if the command is not
  854. X * recognized).
  855. X * The commands and indices accepted are listed in the include file
  856. X * "cmds.h".
  857. X */
  858. Xcmdparse(buf, len)
  859. Xchar *buf;
  860. Xint len;
  861. X{
  862. X    register char *cmdp, *bufp;    /* command, buffer ptrs. */
  863. X    register struct    cmdtab    *ct;    /* cmd table ptr */
  864. X    register int i;            /* index in cmd table */
  865. X    int    clen;            /* length of this command */
  866. X    
  867. X    for (ct = &cmdtab[1], i = 1; ct->c_name != NULL; ct++, i++) {
  868. X        clen = ct->c_len;
  869. X        if (len < clen)        /* buffer shorter than command? */
  870. X            continue;
  871. X        /* case-insensitive matching of command names */
  872. X        for (cmdp = ct->c_name, bufp = buf;
  873. X             clen > 0 && *cmdp == toupper(*bufp);
  874. X             cmdp++, bufp++, clen--)
  875. X            ;
  876. X        if (clen == 0) {        /* success */
  877. X            /* sendmail compatibility */
  878. X            if (i == ONEX || i == VERB)
  879. X                i = NOOP;
  880. X            return i;
  881. X        }
  882. X    }
  883. X    return 0;
  884. X}
  885. X
  886. Xstatic    char    *to;            /* ptr. into request buffer */
  887. X
  888. X/*
  889. X * Parse the recipient spec in the buffer.  Start by stripping the
  890. X * command off the front of the buffer.  Then call canon() to convert
  891. X * the recpient name into a format acceptable to the mailer daemon
  892. X * (ie. the original multiple-at-sign format).
  893. X * Returns TRUE if parsed successfully, FALSE otherwise.
  894. X */
  895. X/* ARGSUSED len */
  896. Xparse_rcpt(buf, len)
  897. Xchar *buf;                /* command buffer */
  898. Xint len;                /* size of buffer string */
  899. X{
  900. X    register char *from;        /* ptr to recipient name */
  901. X    char *end;
  902. X    
  903. X    from = &buf[cmdtab[RCPT].c_len];
  904. X    while (*from == ' ' || *from == '\t')
  905. X        from++;
  906. X    if (*from == '<') {
  907. X        end = index(from++, '>');
  908. X        if (end == 0) {
  909. X            (void) printf("no > at end of string\n");
  910. X            return FALSE;
  911. X        }
  912. X        *end = 0;
  913. X    }
  914. X    if (rcptlast) {
  915. X        rcptlast += strlen(rcptlast);
  916. X        *rcptlast++ = ' ';
  917. X    } else
  918. X        rcptlast = rcptlist;
  919. X    /* NB: we use the canonical name even if `bad' */
  920. X    if (canon(from, rcptlast))    /* canonicalize */
  921. X#ifdef DEBUG
  922. X        (void) printf("parsed ok: %s\n", rcptlast);
  923. X    else
  924. X        (void) printf("parsed bad: %s\n", rcptlast);
  925. X#endif
  926. X    ;
  927. X    return TRUE;
  928. X}
  929. X
  930. X/*
  931. X * Canonicalize the smtp-style path pointed to by from into the buffer
  932. X * pointed to by the external static variable to.  The result will be
  933. X * a string containing the multiple-at-sign form, as desired by the
  934. X * mailer daemon.  Also removes the '\' escape characters.
  935. X * The procedure follwed is recursive: this routine is recursively
  936. X * called for each "@host" in the from string.
  937. X * Returns TRUE if successful, or FALSE if the format of the recipient
  938. X * name is bad.
  939. X */
  940. Xrcanon(from)
  941. Xregister char    *from;            /* start of string to canonicalize */
  942. X{
  943. X    register char    *end;        /* end of this part of path */
  944. X    register int    escseen;    /* escape character seen */
  945. X    int    atseen;            /* '@' seen in mailbox */
  946. X    
  947. X    escseen = atseen = FALSE;
  948. X    if (*from == '@') {        /* host name; find end */
  949. X        for (end = from; *end != '\0'; end++) {
  950. X            if (escseen)
  951. X                escseen = FALSE;
  952. X            else if (*end == '\\') /* escape? */
  953. X                escseen = TRUE;
  954. X            else if (*end == ',' || *end == ':')
  955. X                break;
  956. X        }
  957. X        if (*end == '\0' || !rcanon(end+1)) { /* bad format? */
  958. X#ifdef PICKY /*{*/
  959. X            (void) printf("no mailbox found\n");
  960. X            return FALSE;
  961. X        } else
  962. X#else
  963. X        }
  964. X#endif                /* PICKY */
  965. X        {
  966. X            escseen = FALSE;
  967. X            for (*from = '%'; from < end; from++) { /* copy into to buffer */
  968. X                if (escseen)
  969. X                    escseen = FALSE;
  970. X                else if (*from == '\\') {
  971. X                    escseen = TRUE;
  972. X                    continue;
  973. X                }
  974. X                *to++ = *from;
  975. X            }
  976. X            *to = '\0';
  977. X            return TRUE;
  978. X        }
  979. X    } else {
  980. X        for (; *from; from++) {    /* copy mailbox */
  981. X            if (escseen)
  982. X                escseen = FALSE;
  983. X            else if (*from == '\\') {
  984. X                escseen = TRUE;
  985. X                continue;
  986. X            } else if (*from == '@') { /* end of username? */
  987. X                (void) printf("found @ in mailbox\n");
  988. X                *from = '%';
  989. X                atseen = TRUE;
  990. X            }
  991. X            *to++ = *from;
  992. X        }
  993. X        *to = 0;
  994. X        return atseen;
  995. X    }
  996. X}
  997. X
  998. X/* Time to live elapsed or io error. */
  999. Xdeath(weapon)
  1000. X{
  1001. X#ifdef SIMPLELOG
  1002. X    simplelog(weapon);
  1003. X#endif
  1004. X    (void) printf("Time to die.\n");
  1005. X    /*(void) unlink(dataname);*/
  1006. X    exit(1);
  1007. X}
  1008. X
  1009. Xalarmtr()
  1010. X{
  1011. X    death(E_TEMPFAIL);
  1012. X}
  1013. X
  1014. Xcanon(in, out)
  1015. Xchar    *in, *out;
  1016. X{
  1017. X    char *at;
  1018. X
  1019. X    to = out;
  1020. X    if (funnychars(in) || !rcanon(in) || (at = rindex(out, '%')) == 0)
  1021. X        return(FALSE);
  1022. X    *at = '@';
  1023. X    return TRUE;
  1024. X}
  1025. X
  1026. Xfunnychars(str)
  1027. Xregister char *str;
  1028. X{
  1029. X
  1030. X    for (;;)
  1031. X        switch(*str++) {
  1032. X        case '^':
  1033. X        case '&':
  1034. X        case '>':
  1035. X        case '<':
  1036. X        case '`':
  1037. X        case '|':
  1038. X        case ';':
  1039. X        case '\'':
  1040. X            return TRUE;
  1041. X
  1042. X        case 0:
  1043. X            return FALSE;
  1044. X        }
  1045. X}
  1046. X
  1047. X#ifdef SIMPLELOG
  1048. Xsimplelog(retcode)
  1049. X{
  1050. X    char buf[1024], *bptr, *status;
  1051. X    int fd;
  1052. X    time_t t;
  1053. X    extern char *ctime();
  1054. X    extern time_t time();
  1055. X
  1056. X    t = time(&t);
  1057. X    switch (retcode) {
  1058. X    case E_CANTOPEN:
  1059. X        status = "OPEN FAILED";
  1060. X        break;
  1061. X    case E_IOERR:
  1062. X        status = "IO ERROR";
  1063. X        break;
  1064. X    case E_TEMPFAIL:
  1065. X        status = "TIMED OUT";
  1066. X        break;
  1067. X    case 0:
  1068. X        status = "OK";
  1069. X        break;
  1070. X    default:
  1071. X        status = "DELIVERY FAILURE";
  1072. X        break;
  1073. X    }
  1074. X    if (*mailfrom == 0)
  1075. X        strcpy(mailfrom, "UNKNOWN");
  1076. X    if (*rcptto == 0)
  1077. X        strcpy(rcptto, "UNKNOWN");
  1078. X    (void) sprintf(buf, "%s %s %s %s", mailfrom, rcptto, status, ctime(&t));
  1079. X    for (bptr = buf; *bptr; bptr++)
  1080. X        if (*bptr == '\n' || *bptr == '\r')
  1081. X            *bptr = ' ';
  1082. X    strcat(bptr, "\n");
  1083. X    if ((fd = open("/tmp/smtpd.log", O_WRONLY|O_APPEND)) >= 0) {
  1084. X        (void) write(fd, buf, strlen(buf));
  1085. X        (void) close(fd);
  1086. X    }
  1087. X}
  1088. X#endif
  1089. X
  1090. Xbitch(buf, fo)
  1091. Xchar *buf;
  1092. XFILE *fo;
  1093. X{
  1094. X    char gripe[MAXSTR], *nlptr;
  1095. X
  1096. X    if ((nlptr = index(buf, '\n')) != 0)
  1097. X        *nlptr = 0;
  1098. X    (void) sprintf(gripe, "502 %s ... Not recognized\n", buf);
  1099. X    (void) tputs(gripe, fo);
  1100. X}
  1101. SHAR_EOF
  1102. if test 12608 -ne "`wc -c < 'dconverse.c'`"
  1103. then
  1104.     echo shar: "error transmitting 'dconverse.c'" '(should have been 12608 characters)'
  1105. fi
  1106. fi
  1107. echo shar: "extracting 'misc.c'" '(4018 characters)'
  1108. if test -f 'misc.c'
  1109. then
  1110.     echo shar: "will not over-write existing file 'misc.c'"
  1111. else
  1112. sed 's/^X//' << \SHAR_EOF > 'misc.c'
  1113. X
  1114. X/*
  1115. X**  Miscellaneous support functions for smtp (borrowed from smail)
  1116. X*/
  1117. X
  1118. X# include    "smtp.h"
  1119. X#ifdef BSD
  1120. X# include    <sys/timeb.h>
  1121. X#endif
  1122. X#ifdef SYSV
  1123. X# include    <sys/utsname.h>
  1124. X#endif
  1125. X
  1126. Xchar hostdomain[256];
  1127. Xchar hostname[256];
  1128. X
  1129. Xextern struct tm *localtime();
  1130. X
  1131. Xstruct tm *gmt, *loc;        /* GMT and local time structure    */
  1132. Xtime_t now;            /* current system time        */
  1133. Xchar nows[50];            /* time in ctime format        */
  1134. Xchar arpanows[50];        /* time in arpa format        */
  1135. X
  1136. Xsetdates()
  1137. X{
  1138. X    time_t time();
  1139. X    struct tm *gmtime();
  1140. X    char *ctime(), *arpadate();
  1141. X
  1142. X    (void) time(&now);
  1143. X    (void) strcpy(nows, ctime(&now));
  1144. X    gmt = gmtime(&now);
  1145. X    loc = localtime(&now);
  1146. X    (void) strcpy(arpanows, arpadate(nows));
  1147. X}
  1148. X
  1149. X/*
  1150. X**  Note: This routine was taken from sendmail
  1151. X**
  1152. X**  ARPADATE -- Create date in ARPANET format
  1153. X**
  1154. X**    Parameters:
  1155. X**        ud -- unix style date string.  if NULL, one is created.
  1156. X**
  1157. X**    Returns:
  1158. X**        pointer to an ARPANET date field
  1159. X**
  1160. X**    Side Effects:
  1161. X**        none
  1162. X**
  1163. X**    WARNING:
  1164. X**        date is stored in a local buffer -- subsequent
  1165. X**        calls will overwrite.
  1166. X**
  1167. X**    Bugs:
  1168. X**        Timezone is computed from local time, rather than
  1169. X**        from whereever (and whenever) the message was sent.
  1170. X**        To do better is very hard.
  1171. X**
  1172. X**        Some sites are now inserting the timezone into the
  1173. X**        local date.  This routine should figure out what
  1174. X**        the format is and work appropriately.
  1175. X*/
  1176. X
  1177. Xchar *
  1178. Xarpadate(ud)
  1179. X    register char *ud;
  1180. X{
  1181. X    register char *p;
  1182. X    register char *q;
  1183. X    static char b[40];
  1184. X    extern char *ctime();
  1185. X    register int i;
  1186. X#ifndef BSD
  1187. X    extern char *tzname[];
  1188. X    extern long timezone;
  1189. X    char dspace[40];
  1190. X    time_t t, time();
  1191. X    int dst;            /* dst active */
  1192. X    long tz;
  1193. X#else
  1194. X    /* V7 and 4BSD */
  1195. X    struct timeb t;
  1196. X    extern struct timeb *ftime();
  1197. X    extern char *timezone();
  1198. X#endif
  1199. X
  1200. X    /*
  1201. X    **  Get current time.
  1202. X    **    This will be used if a null argument is passed and
  1203. X    **    to resolve the timezone.
  1204. X    */
  1205. X
  1206. X#ifndef BSD
  1207. X    (void) time(&t);
  1208. X    if (ud == NULL)
  1209. X        ud = ctime(&t);
  1210. X#else
  1211. X    /* V7 or 4BSD */
  1212. X    ftime(&t);
  1213. X    if (ud == NULL)
  1214. X        ud = ctime(&t.time);
  1215. X#endif
  1216. X
  1217. X    /*
  1218. X    **  Crack the UNIX date line in a singularly unoriginal way.
  1219. X    */
  1220. X
  1221. X    q = b;
  1222. X
  1223. X    p = &ud[0];        /* Mon */
  1224. X    *q++ = *p++;
  1225. X    *q++ = *p++;
  1226. X    *q++ = *p++;
  1227. X    *q++ = ',';
  1228. X    *q++ = ' ';
  1229. X
  1230. X    p = &ud[8];        /* 16 */
  1231. X    if (*p == ' ')
  1232. X        p++;
  1233. X    else
  1234. X        *q++ = *p++;
  1235. X    *q++ = *p++;
  1236. X    *q++ = ' ';
  1237. X
  1238. X    p = &ud[4];        /* Sep */
  1239. X    *q++ = *p++;
  1240. X    *q++ = *p++;
  1241. X    *q++ = *p++;
  1242. X    *q++ = ' ';
  1243. X
  1244. X    p = &ud[22];        /* 1979 */
  1245. X    *q++ = *p++;
  1246. X    *q++ = *p++;
  1247. X    *q++ = ' ';
  1248. X
  1249. X    p = &ud[11];        /* 01:03:52 */
  1250. X    for (i = 8; i > 0; i--)
  1251. X        *q++ = *p++;
  1252. X
  1253. X                /* -PST or -PDT */
  1254. X#ifndef BSD
  1255. X    dst = localtime(&t)->tm_isdst;
  1256. X    tz = timezone - (dst ? 3600 : 0);
  1257. X    p = tzname[dst];
  1258. X#else
  1259. X    p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
  1260. X    if (p[3] != '\0')
  1261. X    {
  1262. X        /* hours from GMT */
  1263. X        p += 3;
  1264. X        *q++ = *p++;
  1265. X        if (p[1] == ':')
  1266. X            *q++ = '0';
  1267. X        else
  1268. X            *q++ = *p++;
  1269. X        *q++ = *p++;
  1270. X        p++;        /* skip ``:'' */
  1271. X        *q++ = *p++;
  1272. X        *q++ = *p++;
  1273. X    }
  1274. X    else
  1275. X#endif
  1276. X    {
  1277. X        *q++ = ' ';
  1278. X        while (*p) *q++ = *p++;
  1279. X    }
  1280. X#ifndef BSD
  1281. X    if (tz != 0) {
  1282. X        (void) sprintf (q, " (%c%02d%02d)", 
  1283. X            ((tz > 0) ? '-' : '+'),
  1284. X            abs(tz/3600),
  1285. X            abs(tz%3600)/60);
  1286. X        q += strlen (q);
  1287. X    }
  1288. X#endif
  1289. X
  1290. X    *q = '\0';
  1291. X    return (b);
  1292. X}
  1293. X
  1294. X/*
  1295. X**
  1296. X**  getmynames(): what is my host name and host domain?
  1297. X**
  1298. X**  Hostname set by -h, failing that by #define HOSTNAME, failing
  1299. X**  that by gethostname() or uname().
  1300. X**  
  1301. X**  Hostdomain set by -h, failing that by #define HOSTDOMAIN,
  1302. X**  failing that as hostname.MYDOM, or as just hostname.
  1303. X**
  1304. X**  See defs.h for the inside story.
  1305. X**
  1306. X*/
  1307. X
  1308. Xgetmynames()
  1309. X{
  1310. X#ifdef HOSTNAME
  1311. X    if (!*hostname)
  1312. X        (void) strcpy(hostname, HOSTNAME);
  1313. X#endif
  1314. X#ifdef BSD
  1315. X    if (!*hostname)
  1316. X        gethostname(hostname, SMLBUF - 1);
  1317. X#endif
  1318. X#ifdef SYSV
  1319. X    if (!*hostname) {
  1320. X        struct utsname site;
  1321. X
  1322. X        if (uname(&site) == 0)
  1323. X            (void) strcpy(hostname, site.nodename);
  1324. X    }
  1325. X#endif
  1326. X    if (!*hostname)
  1327. X        return -1;
  1328. X#ifdef HOSTDOMAIN
  1329. X    if (!*hostdomain)
  1330. X        (void) strcpy(hostdomain, HOSTDOMAIN);
  1331. X#endif
  1332. X#ifdef MYDOM
  1333. X    if (!*hostdomain)
  1334. X        (void) strcat(strcpy(hostdomain, hostname), MYDOM);
  1335. X#endif
  1336. X    if (!*hostdomain)
  1337. X        (void) strcpy(hostdomain, hostname);
  1338. X
  1339. X    return 1;
  1340. X}
  1341. SHAR_EOF
  1342. if test 4018 -ne "`wc -c < 'misc.c'`"
  1343. then
  1344.     echo shar: "error transmitting 'misc.c'" '(should have been 4018 characters)'
  1345. fi
  1346. fi
  1347. echo shar: "extracting 'miscerrs.h'" '(197 characters)'
  1348. if test -f 'miscerrs.h'
  1349. then
  1350.     echo shar: "will not over-write existing file 'miscerrs.h'"
  1351. else
  1352. sed 's/^X//' << \SHAR_EOF > 'miscerrs.h'
  1353. X/* these error numbers are local to the smtp programs, used by bomb() */
  1354. X#define    E_USAGE        -1
  1355. X#define E_NOHOST    -2
  1356. X#define    E_CANTOPEN    -3
  1357. X#define E_OSFILE    -4
  1358. X#define E_IOERR        -5
  1359. X#define E_TEMPFAIL    -6
  1360. SHAR_EOF
  1361. if test 197 -ne "`wc -c < 'miscerrs.h'`"
  1362. then
  1363.     echo shar: "error transmitting 'miscerrs.h'" '(should have been 197 characters)'
  1364. fi
  1365. fi
  1366. echo shar: "extracting 'mx.c'" '(5751 characters)'
  1367. if test -f 'mx.c'
  1368. then
  1369.     echo shar: "will not over-write existing file 'mx.c'"
  1370. else
  1371. sed 's/^X//' << \SHAR_EOF > 'mx.c'
  1372. X#include <stdio.h>
  1373. X#include <netdb.h>
  1374. X#include <sysexits.h>
  1375. X#include <sys/errno.h>
  1376. X#include <sys/types.h>
  1377. X#include <sys/socket.h>
  1378. X#include <netinet/in.h>
  1379. X#include <arpa/nameser.h>
  1380. X#include "miscerrs.h"
  1381. X
  1382. X/* imports */
  1383. Xextern int errno, h_errno;
  1384. Xextern char *malloc(), *strcpy(), *inet_ntoa();
  1385. X
  1386. X/* exports */
  1387. Xint mxconnect();
  1388. X
  1389. X/* private */
  1390. X#define MAXMXLIST 10
  1391. Xstatic struct mxitem {
  1392. X    char *host;
  1393. X    u_short pref;
  1394. X    u_char localflag;
  1395. X} MXlist[MAXMXLIST + 1];
  1396. Xstatic char *strsave();
  1397. Xstatic int buildmxlist();
  1398. Xstatic void mxsave(), mxinsert(), mxlocal();
  1399. Xstatic struct hostent *getmxhost();
  1400. X
  1401. X#ifdef MXMAIN
  1402. X
  1403. X#define bomb return
  1404. X
  1405. Xmain(argc, argv)
  1406. X    char **argv;
  1407. X{    int fd;
  1408. X    char buf[BUFSIZ], *crlf, *index();
  1409. X    struct mxitem *mxp;
  1410. X
  1411. X    for (;;) {
  1412. X        printf("domain: ");
  1413. X        if (argc > 1)
  1414. X            strcpy(buf, argv[1]);
  1415. X        else if (gets(buf) == 0)
  1416. X            break;
  1417. X        if ((fd = mxconnect(buf)) >= 0)
  1418. X            if (read(fd, buf, 512) > 0) {
  1419. X                if ((crlf = index(buf, '\r')) != 0)
  1420. X                    strcpy(crlf, "\n");
  1421. X                puts(buf);
  1422. X            } else
  1423. X                perror("read");
  1424. X        close(fd);
  1425. X        if (argc > 1)
  1426. X            break;
  1427. X        for (mxp = MXlist; mxp < MXlist + MAXMXLIST + 1; mxp++)
  1428. X            mxp->host = 0;
  1429. X    }
  1430. X    return 0;
  1431. X}
  1432. X#endif
  1433. X
  1434. Xmxconnect(host)
  1435. X    char *host;
  1436. X{    int s, lport, mxfatal;
  1437. X    char **addr, errbuf[256];
  1438. X    struct hostent *hp;
  1439. X    struct servent *sp;
  1440. X    struct sockaddr_in sin;
  1441. X    struct mxitem *mxp;
  1442. X
  1443. X    mxfatal = buildmxlist(host);
  1444. X    if (MXlist[0].host == 0)
  1445. X        MXlist[0].host = host;
  1446. X    if ((sp = getservbyname ("smtp", "tcp")) == NULL) {
  1447. X        (void)fprintf(stderr,"unknown service TCP/smtp\n");
  1448. X        bomb(E_OSFILE);
  1449. X    }
  1450. X    (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) 0, 0);
  1451. X
  1452. X    /* slop in the loop -- i hate the socket dance */
  1453. X    for (mxp = MXlist; mxp->host; mxp++) {
  1454. X        if ((s = rresvport(&lport)) < 0) {
  1455. X            perror("rresvport");
  1456. X            bomb(E_CANTOPEN);
  1457. X        }
  1458. X        if ((hp = getmxhost(mxp->host)) == 0) {
  1459. X            (void) close(s);
  1460. X            if (mxfatal)
  1461. X                bomb(E_NOHOST);
  1462. X            continue;
  1463. X        }
  1464. X        bzero((char *)&sin, sizeof(sin));
  1465. X        sin.sin_port = sp->s_port;
  1466. X        sin.sin_family = hp->h_addrtype;
  1467. X        for (addr = hp->h_addr_list; *addr; addr++) {
  1468. X            bcopy(*addr, (char *) &sin.sin_addr, hp->h_length);
  1469. X            if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  1470. X                sprintf(errbuf, "%s [%s]", mxp->host, inet_ntoa(sin.sin_addr));
  1471. X                perror(errbuf);
  1472. X                continue;
  1473. X            }
  1474. X            return s;
  1475. X        }
  1476. X        close(s);
  1477. X    }
  1478. X
  1479. X    bomb(E_TEMPFAIL);
  1480. X}
  1481. X
  1482. X/* return 1 for fatal MX error (authoritative NXDOMAIN), 0 o.w. */
  1483. Xstatic int
  1484. Xbuildmxlist(host)
  1485. X    char *host;
  1486. X{    register HEADER *hp;
  1487. X    register char *cp;
  1488. X    register int n;
  1489. X    char q[PACKETSZ], a[PACKETSZ];    /* query, answer */
  1490. X    char *eom, *bp;
  1491. X    int buflen, ancount, qdcount;
  1492. X    char hostbuf[BUFSIZ+1];
  1493. X    u_short preference, reclen;
  1494. X
  1495. X    if ((n = res_mkquery(QUERY, host, C_IN, T_MX, (char *) 0, 0, (struct rrec *) 0, q, sizeof(q))) < 0)
  1496. X        return 0;
  1497. X    n = res_send(q, n, a, sizeof(a));
  1498. X    if (n < 0)
  1499. X        return 0;
  1500. X    eom = a + n;
  1501. X    hp = (HEADER *) a;
  1502. X    ancount = ntohs(hp->ancount);
  1503. X    qdcount = ntohs(hp->qdcount);
  1504. X    if (hp->rcode != NOERROR || ancount == 0)
  1505. X        return hp->rcode == NXDOMAIN && hp->aa;
  1506. X    bp = hostbuf;
  1507. X    buflen = sizeof(hostbuf);
  1508. X    cp = a + sizeof(HEADER);
  1509. X    while (--qdcount >= 0)
  1510. X        cp += dn_skip(cp) + QFIXEDSZ;
  1511. X    /* TODO: if type is CNAME, reissue query */
  1512. X    while (--ancount >= 0 && cp < eom) {
  1513. X        cp += dn_skip(cp)    /* name */
  1514. X            + sizeof(u_short)    /* type */    
  1515. X            + sizeof(u_short)    /* class */
  1516. X            + sizeof(u_long);    /* ttl (see rfc973) */
  1517. X        reclen = _getshort(cp);
  1518. X        cp += sizeof(u_short);
  1519. X        preference = _getshort(cp);
  1520. X        if ((n = dn_expand(a, eom, cp + sizeof(u_short), bp, buflen)) < 0)
  1521. X            break;
  1522. X        mxsave(bp, preference);
  1523. X        cp += reclen;
  1524. X    }
  1525. X    mxlocal();
  1526. X    return 0;
  1527. X}
  1528. X
  1529. X/* NOT TODO: issue WKS query.  (just try to connect.) */
  1530. X
  1531. Xstatic void
  1532. Xmxsave(host, pref)
  1533. X    char *host;
  1534. X    u_short pref;
  1535. X{    struct mxitem *mxp;
  1536. X    int localflag;
  1537. X    static char thishost[64];
  1538. X
  1539. X    if (*thishost == 0)
  1540. X        gethostname(thishost, sizeof(thishost));
  1541. X
  1542. X    if (MXlist[MAXMXLIST].host)
  1543. X        return;                /* full */
  1544. X
  1545. X    localflag = (strcmp(thishost, host) == 0);
  1546. X
  1547. X    /* insertion sort */
  1548. X    for (mxp = MXlist; mxp < MXlist + MAXMXLIST; mxp++) {
  1549. X        if (mxp->host == 0) {
  1550. X            mxinsert(mxp, host, pref, localflag);
  1551. X            return;
  1552. X        }
  1553. X        if (pref < mxp->pref) {
  1554. X            mxinsert(mxp, host, pref, localflag);
  1555. X            return;
  1556. X        }
  1557. X        if (pref == mxp->pref) {
  1558. X            if (mxp->localflag)
  1559. X                return;
  1560. X            if (localflag) {
  1561. X                mxp->host = strsave(host);
  1562. X                mxp->pref = pref;
  1563. X                mxp->localflag = localflag;
  1564. X                (++mxp)->host = 0;
  1565. X                return;
  1566. X            }
  1567. X            mxinsert(mxp, host, pref, localflag);
  1568. X            return;
  1569. X        }
  1570. X    }
  1571. X}
  1572. X
  1573. Xstatic void
  1574. Xmxinsert(mxlistp, host, pref, localflag)
  1575. X    struct mxitem *mxlistp;
  1576. X    char *host;
  1577. X    u_short pref;
  1578. X{    register struct mxitem *mxp;
  1579. X
  1580. X    for (mxp = MXlist + MAXMXLIST - 1; mxp > mxlistp; --mxp)
  1581. X        *mxp = mxp[-1];
  1582. X    mxp->host = strsave(host);
  1583. X    mxp->pref = pref;
  1584. X    mxp->localflag = localflag;
  1585. X}
  1586. X
  1587. Xstatic char *
  1588. Xstrsave(str)
  1589. X    register char *str;
  1590. X{    register char *rval;
  1591. X
  1592. X    if ((rval = malloc(strlen(str) + 1)) == 0) {
  1593. X        perror("malloc");
  1594. X        bomb(-EX_SOFTWARE);
  1595. X    }
  1596. X    strcpy(rval, str);
  1597. X    return rval;
  1598. X}
  1599. X
  1600. Xstatic void
  1601. Xmxlocal()
  1602. X{    register struct mxitem *mxp;
  1603. X
  1604. X    if (MXlist[0].host == 0)
  1605. X        return;
  1606. X
  1607. X    for (mxp = MXlist; mxp->host; mxp++) {
  1608. X        if (mxp->localflag) {
  1609. X            mxp->host = 0;
  1610. X            break;
  1611. X        }
  1612. X    }
  1613. X}
  1614. X
  1615. Xstatic struct hostent *
  1616. Xgetmxhost(host)
  1617. X    char *host;
  1618. X{    struct hostent *hp, *gethostbyname();
  1619. X
  1620. X    if ((hp = gethostbyname(host)) != 0)
  1621. X        return hp;
  1622. X
  1623. X    switch(h_errno) {
  1624. X
  1625. X    case HOST_NOT_FOUND:
  1626. X        (void) fprintf(stderr, "unknown host (%s).\n", host);
  1627. X        break;
  1628. X
  1629. X    case TRY_AGAIN:
  1630. X        (void) fprintf(stderr, "name server not responding (%s).\n", host);
  1631. X        break;
  1632. X
  1633. X    case NO_RECOVERY:
  1634. X        (void) fprintf(stderr, "name server error (%s).\n", host);
  1635. X        break;
  1636. X        
  1637. X    case NO_ADDRESS:
  1638. X        (void) fprintf(stderr, "no IP address (%s).\n", host);
  1639. X        break;
  1640. X    
  1641. X    default:
  1642. X        (void) fprintf(stderr, "unknown resolver error (%s).\n", host);
  1643. X        break;
  1644. X    }
  1645. X    return 0;
  1646. X}
  1647. SHAR_EOF
  1648. if test 5751 -ne "`wc -c < 'mx.c'`"
  1649. then
  1650.     echo shar: "error transmitting 'mx.c'" '(should have been 5751 characters)'
  1651. fi
  1652. fi
  1653. echo shar: "extracting 'netio.c'" '(1442 characters)'
  1654. if test -f 'netio.c'
  1655. then
  1656.     echo shar: "will not over-write existing file 'netio.c'"
  1657. else
  1658. sed 's/^X//' << \SHAR_EOF > 'netio.c'
  1659. X#ifndef lint
  1660. Xstatic char *sccsid = "@(#)netio.c    1.7 87/07/31";
  1661. X#endif lint
  1662. X
  1663. X#include "smtp.h"
  1664. X#include <setjmp.h>
  1665. X
  1666. X#ifdef NOBOMB
  1667. X#define bomb exit
  1668. X#endif
  1669. X
  1670. Xchar *strcpy(), *strncat();
  1671. X
  1672. Xint hooting = 0;        /* true if not server */
  1673. X
  1674. Xint
  1675. Xtgets(line, size, fi)        /* fgets from TCP */
  1676. Xchar *line;
  1677. Xint size;
  1678. XFILE *fi;
  1679. X{
  1680. X    register char *cr;
  1681. X
  1682. X    *line = 0;
  1683. X    if (fgets(line, size, fi) == NULL)
  1684. X        return -1;
  1685. X    if (ferror(fi)) {
  1686. X        perror("error reading from smtp");
  1687. X        bomb(E_IOERR);
  1688. X    }
  1689. X
  1690. X    /* convert \r\n -> \n */
  1691. X    cr = line + strlen(line) - 2;
  1692. X    if (cr >= line && *cr == '\r' && *(cr+1) == '\n') {    /* CRLF there? */
  1693. X        *cr++ = '\n';
  1694. X        *cr = 0;
  1695. X    } else                /* no CRLF present */
  1696. X        cr += 2;        /* point at NUL byte */
  1697. X
  1698. X#ifdef HOOTING
  1699. X    if (hooting) (void) printf("<<< %s", line);
  1700. X#endif
  1701. X    if (feof(fi)) {
  1702. X        perror("read eof from smtp");
  1703. X        bomb(E_IOERR);
  1704. X    }
  1705. X    return cr - line;
  1706. X}
  1707. X
  1708. Xint
  1709. Xtputs(line, fo)            /* fputs to TCP */
  1710. Xchar *line;
  1711. XFILE *fo;
  1712. X{
  1713. X    char buf[MAXSTR];
  1714. X    register char *nl;
  1715. X    extern int debug;
  1716. X
  1717. X    (void) strcpy(buf, line);
  1718. X#ifdef HOOTING
  1719. X    if (hooting) (void) printf(">>> %s", buf);
  1720. X#endif
  1721. X    /* replace terminating \n by \r\n */
  1722. X    nl = buf + strlen(buf) - 1;        /* presumably \n */
  1723. X    if (nl >= buf && *nl=='\n') {        /* if it is ... */
  1724. X        *nl++ = '\r';
  1725. X        *nl++ = '\n';
  1726. X        *nl = 0;
  1727. X    } else
  1728. X        printf("unterminated line: <%s>\n", buf);
  1729. X
  1730. X    (void) fputs(buf, fo);
  1731. X    (void) fflush(fo);
  1732. X    if (ferror(fo)) {
  1733. X        (void) perror("error writing to smtp");
  1734. X        bomb(E_IOERR);
  1735. X    }
  1736. X    return 0;
  1737. X}
  1738. SHAR_EOF
  1739. if test 1442 -ne "`wc -c < 'netio.c'`"
  1740. then
  1741.     echo shar: "error transmitting 'netio.c'" '(should have been 1442 characters)'
  1742. fi
  1743. fi
  1744. echo shar: "extracting 'smtp.8'" '(4836 characters)'
  1745. if test -f 'smtp.8'
  1746. then
  1747.     echo shar: "will not over-write existing file 'smtp.8'"
  1748. else
  1749. sed 's/^X//' << \SHAR_EOF > 'smtp.8'
  1750. X.TH SMTP 8 local "Public Domain"
  1751. X.DA "4 May 1987"
  1752. X.SH NAME
  1753. Xsmtp, smtpd, in.smtpd \- SMTP talker and listeners
  1754. X.br
  1755. Xsmtpqer, runsmtpq, smtpq \- SMTP enqueuing, queue running and listing
  1756. X.br
  1757. Xcleansmtpq, returnsmtpmail \- SMTP queue cleaning and mail returning
  1758. X.SH SYNOPSIS
  1759. X.B /usr/lib/mail/smtp
  1760. X[
  1761. X.B \-h
  1762. Xhelohost
  1763. X]
  1764. Xtargethost sender recipient
  1765. X.br
  1766. X.B "cd /usr/spool/smtpq; /usr/lib/mail/smtpd"
  1767. X.br
  1768. X.B "cd /usr/spool/smtpq; /usr/etc/in.smtpd"
  1769. X.RB sourcehost . sourceport
  1770. X.br
  1771. X.B /usr/lib/mail/smtpqer
  1772. X[
  1773. X.B \-h
  1774. Xhelohost
  1775. X]
  1776. Xtargethost sender recipient
  1777. X.br
  1778. X.B /usr/lib/mail/runsmtpq
  1779. X.br
  1780. X.B /usr/lib/mail/smtpq
  1781. X.br
  1782. X.B /usr/lib/mail/cleansmtpq
  1783. X.br
  1784. X.B /usr/lib/mail/returnsmtpmail
  1785. X*.sh ...
  1786. X.SH DESCRIPTION
  1787. XThese routines provide a minimal stand-alone \s-2SMTP\s0 service.
  1788. XIt consists of small programs that can be used with a central mail router like
  1789. X.I upas,
  1790. Xa system of your own construction,
  1791. Xor
  1792. X.IR sendmail .
  1793. X.PP
  1794. X.I smtp
  1795. Xsends the mail message on its standard input to
  1796. X.I targethost
  1797. Xwhich in turn will deliver the message to
  1798. X.I recipient
  1799. Xas being from
  1800. X.IR sender .
  1801. X.I smtp
  1802. Xcan be used with
  1803. X.I sendmail
  1804. Xinstead of the latter's built-in \s-2IPC\s0 mailer.
  1805. XHere is a mailer definition we have used;
  1806. Xyour mileage will vary:
  1807. X.PP
  1808. X.nf
  1809. X.B
  1810. XMether, P=/usr/lib/mail/smtp, F=SsDFuCX, S=11, R=21, A=smtp $h $g $u
  1811. X.fi
  1812. X.PP
  1813. XEvery SMTP talker identifies itself in the
  1814. X``host.domain''
  1815. Xpart of the \s-2SMTP\s0 \s-2HELO\s0 message.
  1816. XNormally
  1817. X.I smtp
  1818. Xuses the
  1819. X.IR gethostname (2)
  1820. Xcall to get the hostname,
  1821. Xand the compiled-in DOMAINNAME,
  1822. Xto identify itself.
  1823. XThe
  1824. X.B \-h
  1825. Xoption allows you to override both values with one string,
  1826. Xi.e.,
  1827. X.BR \-h erewhon.peter.edu.
  1828. XIf you are using 
  1829. X.I sendmail ,
  1830. Xthen
  1831. X.B \-h
  1832. Xshould be added to the Mether definition with ``-h$j''
  1833. X(but this has not yet been tested).
  1834. XIn
  1835. X.IR upas ,
  1836. Xa typical rule is
  1837. X.PP
  1838. X.nf
  1839. X.B
  1840. X^([^!]+)\e.(mil|gov|edu|com|uk|org|net)!(.+)$ | "smtpqer -h \fIdom.ain\fP \e1.\e2 \es \e3"
  1841. X.fi
  1842. X.PP
  1843. X.I smtpd
  1844. Xis a 4.2BSD (or later) network daemon:
  1845. Xit listens on the SMTP port
  1846. X(TCP port 25 usually)
  1847. Xfor an SMTP talker,
  1848. Xreceives a mail message from it
  1849. Xand hands the message to
  1850. X.I cmail
  1851. X(or equivalent other mail system).
  1852. X.I in.smtpd
  1853. Xis a similar 4.3BSD (or later)
  1854. X.I inetd
  1855. Xdaemon:
  1856. Xit expects an SMTP connection on file descriptor zero (0)
  1857. Xand the
  1858. X.I sourcehost
  1859. Xand
  1860. X.I sourceport
  1861. Xas its argument
  1862. X.RI ( sourcehost
  1863. Xin hexademical;
  1864. X.I sourceport
  1865. Xin decimal).
  1866. X.PP
  1867. X.I smtpqer
  1868. Xqueues its standard input
  1869. Xand shell commands to invoke
  1870. X.I smtp
  1871. Xwith
  1872. X.IR smtpqer 's
  1873. Xstandard input and arguments,
  1874. Xand to remove the queued files if
  1875. X.I smtp
  1876. Xis successful.
  1877. XIt then runs
  1878. X.IR runsmtpq .
  1879. X.PP
  1880. X.I runsmtpq
  1881. Xlocks the SMTP queue,
  1882. Xexecutes all the shell command files in the SMTP queue,
  1883. Xand unlocks the SMTP queue.
  1884. X.I runsmtpq
  1885. Xis stolen outright from the SM paper in the proceedings
  1886. Xof the Portland Usenix conference.
  1887. X.PP
  1888. X.I smtpq
  1889. Xshows the contents of the SMTP queue.
  1890. X.PP
  1891. X.I cleansmtpq
  1892. Xreturns to sender mail which has been in the SMTP queue
  1893. Xfor more than three days and removes it from the queue.
  1894. X.PP
  1895. X.I returnsmtpmail
  1896. Xtakes the names of ``envelope'' shell files,
  1897. Xreturns the messages therein
  1898. Xand removes the messages from the SMTP queue.
  1899. X.SH FILES
  1900. X.BR /usr/spool/smtpq "    the SMTP queue"
  1901. X.br
  1902. X.IB queue /*.sh
  1903. X\&    envelopes
  1904. X.br
  1905. X.IB queue /*.msg
  1906. X\&    message contents
  1907. X.br
  1908. X.IB queue /*.errs
  1909. X\&    errors from running
  1910. X.I smtp
  1911. X.br
  1912. X.BR temp.* "    incoming messages, created in"
  1913. X.IR smtpd 's
  1914. Xcurrent directory
  1915. X.SH "SEE ALSO"
  1916. XRFC 821 \- Simple Mail Transfer Protocol, ARPA Internet, NIC, SRI
  1917. X.SH DIAGNOSTICS
  1918. XBy default,
  1919. Xthe talker program exits with the return codes defined in
  1920. X.I <sysexits.h>
  1921. Xfor
  1922. X.IR sendmail .
  1923. XTo disable this,
  1924. Xcompile with -DNOSYSEXITS;
  1925. Xit will exit with code 1 for all errors.
  1926. X.SH HISTORY
  1927. XThe SMTP talker (client) was written by Ian Darwin in 1985,
  1928. Xas a simple telnet-like program
  1929. Xthat just talked from stdin to a remote SMTP.
  1930. XIn late 1986,
  1931. Xit was built into a full talker
  1932. Xwith some functions stolen
  1933. Xfrom the public domain MIT UNIX TCP/IP implementation.
  1934. X.PP
  1935. XThe SMTP listener (daemon) was synthesised by Geoff Collyer
  1936. Xby smashing together an old
  1937. X.I nicname
  1938. Xdaemon written by Ian with more public-domain SMTP code from MIT.
  1939. X.PP
  1940. X.I smtpqer
  1941. Xand
  1942. X.I smtpq
  1943. Xwere written by Geoff Collyer.
  1944. X.IR runsmtpq ,
  1945. X.I cleansmtpq
  1946. Xand
  1947. X.I returnsmtpmail
  1948. Xwere stolen from the SM Portland Usenix paper
  1949. Xand adapted by Geoff Collyer.
  1950. XPeter Honeyman installed it under
  1951. X.I upas
  1952. Xon the Internet and fixed a lot of bugs.
  1953. XSome remain.
  1954. X.SH BUGS
  1955. XThe SMTP implementation is minimal,
  1956. Xand could stand some fleshing out.
  1957. X.PP
  1958. X.I smtp
  1959. Xand
  1960. X.I smtpqer
  1961. Xcould profitably handle multiple recipients on the same machine,
  1962. Xbut dealing with bad recipients would be tricky.
  1963. X.PP
  1964. X.I smtpd
  1965. Xand
  1966. X.I in.smtpd
  1967. Xcreate files named
  1968. X.I temp.*
  1969. Xin their current directories,
  1970. Xso they should be run in the SMTP queue directory.
  1971. X.PP
  1972. X.I smtp
  1973. Xand
  1974. X.I smtpd
  1975. Xlimit connect time to 30 minutes,
  1976. Xwhich can be optimistic.
  1977. SHAR_EOF
  1978. if test 4836 -ne "`wc -c < 'smtp.8'`"
  1979. then
  1980.     echo shar: "error transmitting 'smtp.8'" '(should have been 4836 characters)'
  1981. fi
  1982. fi
  1983. echo shar: "extracting 'smtp.c'" '(4985 characters)'
  1984. if test -f 'smtp.c'
  1985. then
  1986.     echo shar: "will not over-write existing file 'smtp.c'"
  1987. else
  1988. sed 's/^X//' << \SHAR_EOF > 'smtp.c'
  1989. X/*
  1990. X * smtp -- client, send mail to remote smtp server
  1991. X * Set up for 4.2BSD networking system.
  1992. X * Adapted for System V by jv@mh.nl.
  1993. X * TODO:
  1994. X *    better mapping of error numbers.
  1995. X *    allow multiple recipients (maybe)
  1996. X *     send stuff from cmds.h instead of hard-coded here
  1997. X */
  1998. X
  1999. X#define    USAGE "usage: %s [-h helohost] targethost sender recipient\n"
  2000. X
  2001. X#include "smtp.h"
  2002. X#include <sys/uio.h>        /* needed for socket.h */
  2003. X#include <sys/socket.h>
  2004. X#include <netinet/in.h>
  2005. X#include <netdb.h>
  2006. X
  2007. X
  2008. X#ifndef SERVNAME
  2009. X#define SERVNAME "smtp"            /* service we wanna talk to */
  2010. X#endif
  2011. X
  2012. Xchar *progname;
  2013. Xint debug = 0;
  2014. Xextern char hostname[];
  2015. Xextern char hostdomain[];
  2016. Xchar *sendhost = hostdomain;
  2017. XFILE *sfi, *sfo;
  2018. Xchar *host = "None";
  2019. Xchar *strcat(), *strcpy();
  2020. Xstatic char *makedomain();
  2021. X
  2022. X#ifdef HOOTING
  2023. Xextern int hooting;    /* in netio */
  2024. X#endif
  2025. X
  2026. X/*
  2027. X * main - parse arguments and handle options
  2028. X */
  2029. Xmain(argc, argv)
  2030. Xint argc;
  2031. Xchar *argv[];
  2032. X{
  2033. X    register int c;
  2034. X    int errflg = 0;
  2035. X    extern int optind;
  2036. X    extern char *optarg;
  2037. X    char *sender, *recip;
  2038. X
  2039. X    progname = argv[0];
  2040. X    getmynames ();
  2041. X
  2042. X    while ((c = getopt(argc, argv, "dh:")) != EOF)
  2043. X        switch (c) {
  2044. X        case 'd':
  2045. X            ++debug;
  2046. X            break;
  2047. X        case 'h':        /* alternate sending host */
  2048. X            sendhost = optarg;
  2049. X            break;
  2050. X        case '?':
  2051. X        default:
  2052. X            errflg++;
  2053. X            break;
  2054. X        }
  2055. X    if (errflg || (argc - optind) < 3) {
  2056. X        (void) fprintf(stderr, USAGE, progname);
  2057. X        bomb(E_USAGE);
  2058. X    }
  2059. X    host = argv[optind++];
  2060. X    sender = makedomain(argv[optind++], sendhost);
  2061. X    recip  = makedomain(argv[optind++], host);
  2062. X
  2063. X    setup();        /* open connection */
  2064. X
  2065. X
  2066. X#ifdef HOOTING
  2067. X    hooting = 1;
  2068. X#endif
  2069. X    /* hold the conversation */
  2070. X
  2071. X    converse(sender, recip, sfi, sfo, stdin);
  2072. X    (void) sleep(5);    /* drain? */
  2073. X
  2074. X    if (sfo!=NULL)
  2075. X        (void) fclose(sfo);
  2076. X    if (sfi!=NULL)
  2077. X        (void) fclose(sfi);
  2078. X
  2079. X    return 0;
  2080. X}
  2081. X
  2082. X/*
  2083. X * setup -- setup tcp/ip connection to/from server
  2084. X */
  2085. Xsetup()
  2086. X{
  2087. X    struct hostent *hp;
  2088. X    struct servent *sp;
  2089. X    struct sockaddr_in sin;
  2090. X    int s;
  2091. X    extern int errno;
  2092. X
  2093. X    (void) bzero((char *)&sin, sizeof(sin));
  2094. X
  2095. X    if ((hp = gethostbyname(host)) == (struct hostent *) NULL) {
  2096. X        (void) fprintf(stderr, "unknown host (%s).\n", host);
  2097. X        bomb(E_NOHOST);
  2098. X    }
  2099. X
  2100. X    (void) bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
  2101. X
  2102. X    if ((sp = getservbyname (SERVNAME, "tcp")) == NULL) {
  2103. X        (void)fprintf(stderr,"unknown service TCP/%s\n", SERVNAME);
  2104. X        bomb(E_OSFILE);
  2105. X    }
  2106. X    sin.sin_port = sp->s_port;
  2107. X    sin.sin_family = hp->h_addrtype;
  2108. X
  2109. X    if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  2110. X        perror("setup - socket");
  2111. X        bomb(E_CANTOPEN);
  2112. X    }
  2113. X
  2114. X    if (connect(s, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
  2115. X        perror("setup - connect");
  2116. X        /*
  2117. X         * check for conditions that (we think) are temporary;
  2118. X         * try them later; bomb utterly on all others.
  2119. X         */
  2120. X        if (errno == ETIMEDOUT || errno == ECONNREFUSED || 
  2121. X            errno == EHOSTDOWN || errno == EHOSTUNREACH)
  2122. X            bomb(E_TEMPFAIL);
  2123. X        else
  2124. X            bomb(E_CANTOPEN);
  2125. X    }
  2126. X
  2127. X    if (((sfi = fdopen(s, "r")) == (FILE *) NULL) ||
  2128. X        ((sfo = fdopen(s, "w")) == (FILE *) NULL)) {
  2129. X        perror("setup - fdopen");
  2130. X        bomb(E_CANTOPEN);
  2131. X    }
  2132. X/*    setbuf(sfi, (char *) 0);*/
  2133. X}
  2134. X
  2135. X/*
  2136. X * bomb(code) - exit program, map smtp error code into mailsystem code
  2137. X * Codes with E_ are defined in miscerrs.h.
  2138. X * Codes with EX_ are from <sysexits.h>
  2139. X * Lines with FOO are placeholders until we decrypt more appropriate codes.
  2140. X */
  2141. Xbomb(code)
  2142. Xint code;
  2143. X{
  2144. X    if (sfi != NULL)
  2145. X        (void) fclose(sfi);
  2146. X    if (sfo != NULL)
  2147. X        (void) fclose(sfo);
  2148. X
  2149. X#ifdef    EX_OK
  2150. X    switch(code) {
  2151. X    case 451:            /* host not responding */
  2152. X        code = EX_UNAVAILABLE;    /* service unavailable */
  2153. X        break;
  2154. X    case 550:
  2155. X        code = EX_NOUSER;    /* addressee unknown */
  2156. X        break;
  2157. X    case 501:            /* syntax error in address */
  2158. X    case 554:            /* */
  2159. X        code = EX_DATAERR;    /* data format error */
  2160. X        break;
  2161. X    case E_IOERR:
  2162. X        code = EX_IOERR;    /* input/output error */
  2163. X        break;
  2164. X    case E_NOHOST:
  2165. X        code = EX_NOHOST;    /* host name unknown */
  2166. X        break;
  2167. X    case E_OSFILE:            /* no "smtp" -> /etc/services f'd */
  2168. X        code = EX_OSFILE;    /* critical OS file missing */
  2169. X        break;
  2170. X    case E_USAGE:
  2171. X        code = EX_USAGE;    /* command line usage error */
  2172. X        break;
  2173. X    case E_TEMPFAIL:
  2174. X        code = EX_TEMPFAIL;    /* temp failure; user can retry */
  2175. X        break;
  2176. X#if 0
  2177. X    case FOO:
  2178. X        code = EX_OSERR;    /* system error (e.g., can't fork) */
  2179. X        break;
  2180. X    case FOO:
  2181. X        code = EX_NOINPUT;    /* cannot open input */
  2182. X        break;
  2183. X    case FOO:
  2184. X        code = EX_CANTCREAT;    /* can't create (user) output file */
  2185. X        break;
  2186. X    case FOO:
  2187. X        code = EX_PROTOCOL;    /* remote error in protocol */
  2188. X        break;
  2189. X    case FOO:
  2190. X        code = EX_NOPERM;    /* permission denied */
  2191. X        break;
  2192. X#endif    /* NOTDEF */
  2193. X    default:            /* can't happen? */
  2194. X        code = EX_SOFTWARE;    /* internal software error */
  2195. X        break;
  2196. X    }
  2197. X
  2198. X#else    /* has no sysexits */
  2199. X    code = 1;
  2200. X#endif
  2201. X
  2202. X    (void) exit (code);
  2203. X}
  2204. X
  2205. Xstatic char *
  2206. Xmakedomain(addr, domain)
  2207. Xchar *addr, *domain;
  2208. X{
  2209. X    char *rval;
  2210. X    extern char *index(), *malloc();
  2211. X
  2212. X    if (index(addr, '@') != 0)
  2213. X        return addr;
  2214. X
  2215. X    if ((rval = malloc(strlen(addr) + strlen(domain) + 2)) == 0)
  2216. X#ifdef EX_SOFTWARE
  2217. X        bomb(EX_SOFTWARE);    /* can't happen! */
  2218. X#else
  2219. X        bomb (3);
  2220. X#endif
  2221. X    sprintf(rval, "%s@%s", addr, domain);
  2222. X    return rval;
  2223. X}
  2224. SHAR_EOF
  2225. if test 4985 -ne "`wc -c < 'smtp.c'`"
  2226. then
  2227.     echo shar: "error transmitting 'smtp.c'" '(should have been 4985 characters)'
  2228. fi
  2229. fi
  2230. echo shar: "extracting 'smtp.h'" '(1022 characters)'
  2231. if test -f 'smtp.h'
  2232. then
  2233.     echo shar: "will not over-write existing file 'smtp.h'"
  2234. else
  2235. sed 's/^X//' << \SHAR_EOF > 'smtp.h'
  2236. X/* smtp.h */
  2237. X
  2238. X#include "config.h"
  2239. X
  2240. X/* smtp constants and the like */
  2241. X
  2242. X/* tunable constants */
  2243. X#define MAXSTR 10240            /* maximum string length */
  2244. X#define NAMSIZ MAXSTR            /* max file name length */
  2245. X
  2246. X/* standard includes and portability */
  2247. X
  2248. X#include <stdio.h>
  2249. X#include <ctype.h>
  2250. X#include <sys/types.h>
  2251. X#include <errno.h>
  2252. X#include "miscerrs.h"
  2253. X
  2254. X#ifdef BSD
  2255. X#include <strings.h>
  2256. X#include <sys/time.h>
  2257. X#include <sys/wait.h>
  2258. Xextern char *sprintf();
  2259. X# ifndef NOSYSEXITS
  2260. X#  include <sysexits.h>
  2261. X# endif
  2262. X#endif
  2263. X
  2264. X#ifdef SYSV
  2265. X#include <string.h>
  2266. X#include <time.h>
  2267. X#include <fcntl.h>
  2268. X#define    index        strchr
  2269. X#define    rindex        strrchr
  2270. X#define    bcopy(a,b,n)    memcpy(b,a,n)
  2271. X#define    bzero(a,n)    memset(a,'\0',n)
  2272. X#define    SIGCHLD        SIGCLD
  2273. Xextern int sprintf();
  2274. X# ifndef NOSYSEXITS
  2275. X#  include "sysexits.h"
  2276. X# endif
  2277. X#endif
  2278. X
  2279. X#ifndef EX_SOFTWARE
  2280. X# define EX_SOFTWARE    70    /* internal software error */
  2281. X#endif
  2282. X
  2283. X#ifdef SYSLOG
  2284. X# ifdef SYSV
  2285. X#  include "syslog.h"
  2286. X# else
  2287. X#  include <syslog.h>
  2288. X# endif
  2289. X#endif
  2290. X
  2291. X#ifndef TRUE
  2292. X# define TRUE    1
  2293. X# define FALSE    0
  2294. X#endif
  2295. SHAR_EOF
  2296. if test 1022 -ne "`wc -c < 'smtp.h'`"
  2297. then
  2298.     echo shar: "error transmitting 'smtp.h'" '(should have been 1022 characters)'
  2299. fi
  2300. fi
  2301. echo shar: "extracting 'smtpd.c'" '(5297 characters)'
  2302. if test -f 'smtpd.c'
  2303. then
  2304.     echo shar: "will not over-write existing file 'smtpd.c'"
  2305. else
  2306. sed 's/^X//' << \SHAR_EOF > 'smtpd.c'
  2307. X#ifndef lint
  2308. Xstatic char *sccsid = "@(#)smtpd.c    1.7 87/07/31";
  2309. X#endif lint
  2310. X/*
  2311. X * smtpd - SMTP listener: receives SMTP mail & invokes cmail.
  2312. X *    SMTP is either Simple Mail Transfer Protocol or
  2313. X *    Sado-Masochistic Torture Procedure.
  2314. X */
  2315. X
  2316. X#include "smtp.h"
  2317. X#include <signal.h>
  2318. X#include <netdb.h>
  2319. X#include <sys/uio.h>
  2320. X#include <sys/socket.h>
  2321. X#ifdef BSD
  2322. X#include <sgtty.h>
  2323. X#include <sys/wait.h>
  2324. X#endif
  2325. X#include <sys/resource.h>    /* for wait3(2) */
  2326. X#include <netinet/in.h>
  2327. X
  2328. X/* forward declarations */
  2329. XFILE    *popen();
  2330. X
  2331. X#ifdef INETD
  2332. X#ifdef BSD
  2333. Xint    reapchild();
  2334. X#endif
  2335. X#endif
  2336. X
  2337. Xextern    char **environ;
  2338. Xextern    int errno, sys_nerr;
  2339. Xextern    char *sys_errlist[];
  2340. X
  2341. X#ifndef SERVNAME
  2342. X#define SERVNAME "smtp"
  2343. X#endif                /* SERVNAME */
  2344. Xstruct sockaddr_in sin = { AF_INET };
  2345. Xstruct sockaddr_in from;
  2346. X
  2347. Xint debug;
  2348. Xchar *progname;
  2349. Xchar logm[MAXSTR];
  2350. X
  2351. X/*
  2352. X * main - parse arguments and handle options
  2353. X */
  2354. X
  2355. Xmain(argc, argv)
  2356. Xint argc;
  2357. Xchar *argv[];
  2358. X{
  2359. X    int c;
  2360. X    int errflg = 0;
  2361. X    extern int optind;
  2362. X    extern char *optarg;
  2363. X
  2364. X    progname = argv[0];
  2365. X    getmynames ();
  2366. X
  2367. X    while ((c = getopt(argc, argv, "d")) != EOF)
  2368. X        switch (c) {
  2369. X        case 'd':
  2370. X            ++debug;
  2371. X            break;
  2372. X        case '?':
  2373. X        default:
  2374. X            errflg++;
  2375. X            break;
  2376. X        }
  2377. X    if (errflg) {
  2378. X        logit(LOG_CRIT, "Usage: %s [-d]\n", progname);
  2379. X        exit(2);
  2380. X    }
  2381. X
  2382. X    if (optind >= argc)
  2383. X        process();
  2384. X#ifdef INETD
  2385. X    else if (optind == argc - 1) {        /* one argument */
  2386. X        if (sscanf(argv[optind], "%lx.%hd", &from.sin_addr.s_addr,
  2387. X            &from.sin_port) != 2) {
  2388. X            logit(LOG_CRIT,
  2389. X                "in.smtpd: bad arg from inetd: %s\n",
  2390. X                argv[optind]);
  2391. X            exit(2);
  2392. X        }
  2393. X        from.sin_family = AF_INET;
  2394. X        from.sin_addr.s_addr = htonl(from.sin_addr.s_addr);
  2395. X        from.sin_port = htons(from.sin_port);
  2396. X        process();
  2397. X    }
  2398. X#endif                /* INETD */
  2399. X    else {
  2400. X        logit(LOG_CRIT, "%s: too many args\n", progname);
  2401. X        exit(2);
  2402. X    }
  2403. X
  2404. X    return 0;
  2405. X}
  2406. X
  2407. X/*
  2408. X * process - process input file
  2409. X */
  2410. Xprocess()
  2411. X{
  2412. X#ifndef INETD
  2413. X    int s, pid;
  2414. X#endif        /* INETD */
  2415. X    struct servent *sp;
  2416. X
  2417. X    sp = getservbyname(SERVNAME, "tcp");
  2418. X    if (sp == 0) {
  2419. X        logit(LOG_CRIT, "tcp/%s: unknown service\n", SERVNAME);
  2420. X        exit(1);
  2421. X    }
  2422. X    sin.sin_port = sp->s_port;
  2423. X
  2424. X#ifdef INETD
  2425. X    /* connection on fd 0 from inetd */
  2426. X    doit(0, &from);
  2427. X    /* NOTREACHED */
  2428. X    exit(0);
  2429. X#else                    /* INETD */
  2430. X#ifndef DEBUG
  2431. X    if (fork())            /* run in the background */
  2432. X        exit(0);
  2433. X    for (s = 0; s < 10; s++)    /* close most file descriptors */
  2434. X        (void) close(s);
  2435. X    (void) open("/dev/null", 0);    /* reopen them on harmless streams */
  2436. X    (void) dup2(0, 1);
  2437. X    (void) dup2(0, 2);
  2438. X    { int tt = open("/dev/tty", 2);    /* leave current process group */
  2439. X      if (tt > 0) {
  2440. X#ifdef TIOCNOTTY
  2441. X        (void) ioctl(tt, TIOCNOTTY, (char *)0);
  2442. X#endif
  2443. X        (void) close(tt);
  2444. X      }
  2445. X    }
  2446. X#endif                    /* DEBUG */
  2447. X    /* create internet socket s; retry 5 times at 5 s. intervals if no luck */
  2448. X    while ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  2449. X        static int nlog = 0;
  2450. X
  2451. X        if (nlog++ <= 5)
  2452. X            logit(LOG_CRIT, "socket", "");
  2453. X        sleep(5);
  2454. X    }
  2455. X    /* set socket options, notably keepalive */
  2456. X    if (debug) {
  2457. X        int debugval = 1;
  2458. X
  2459. X        if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
  2460. X            (char *)&debugval, sizeof(int)) < 0)
  2461. X            logit(LOG_CRIT, "setsockopt (SO_DEBUG)", "");
  2462. X    }
  2463. X    if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)0, 0) < 0)
  2464. X        logit(LOG_CRIT, "setsockopt (SO_KEEPALIVE)", "");
  2465. X    /* bind socket to SERVNAME (SMTP) port; retry as above on failure */
  2466. X    while (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
  2467. X        static int nlog = 0;
  2468. X
  2469. X        if (nlog++ <= 5)
  2470. X            logit(LOG_CRIT, "bind", "");
  2471. X        sleep(5);
  2472. X    }
  2473. X
  2474. X#ifdef BSD
  2475. X    (void) signal(SIGCHLD, TYPESIG reapchild);
  2476. X#else
  2477. X    (void) signal(SIGCHLD, SIG_IGN);    /* SystemV takes care ... */
  2478. X#endif
  2479. X
  2480. X    /* listen with 10 input buffers on socket (?) */
  2481. X    if (listen(s, 10) == -1)
  2482. X        logit(LOG_CRIT, "listen", "");
  2483. X    for (;;) {
  2484. X        int conn, fromlen = sizeof from;
  2485. X
  2486. X        /* get a connection on fd conn; stores src host addr in from */
  2487. X        conn = accept(s, (struct sockaddr *)&from, &fromlen);
  2488. X        if (conn < 0) {
  2489. X            static int nlog = 0;
  2490. X
  2491. X            if (errno == EINTR)
  2492. X                continue;
  2493. X            if (++nlog <= 5)
  2494. X                logit(LOG_CRIT, "accept", "");
  2495. X            sleep(1);
  2496. X            continue;
  2497. X        }
  2498. X        /* fork a child for this connection */
  2499. X        if ((pid = fork()) < 0)
  2500. X            logit(LOG_CRIT, "can't fork!!", "");
  2501. X        else if (pid == 0) {
  2502. X            (void) signal(SIGCHLD, SIG_DFL);
  2503. X            doit(conn, &from);    /* listen to SMTP dialogue */
  2504. X            /* NOTREACHED */
  2505. X            exit(0);
  2506. X        }
  2507. X        (void) close(conn);
  2508. X    }
  2509. X    /*NOTREACHED*/
  2510. X#endif            /* INETD */
  2511. X}
  2512. X
  2513. X#ifndef INETD
  2514. X#ifdef BSD
  2515. Xreapchild()
  2516. X{
  2517. X    union wait status;
  2518. X
  2519. X    /* gross hack! */
  2520. X    while (wait3(&status, WNOHANG, (struct rusage *)0) > 0);
  2521. X
  2522. X}
  2523. X#endif                /* BSD */
  2524. X#endif            /* INETD */
  2525. X
  2526. X/*
  2527. X * handle some input.  never returns.
  2528. X */
  2529. Xdoit(f, fromaddr)
  2530. Xint f;
  2531. Xstruct sockaddr_in *fromaddr;        /* internet addr of sending host */
  2532. X{
  2533. X    FILE *fi, *fo;
  2534. X
  2535. X    if ((fi = fdopen(f, "r")) == NULL)
  2536. X        logit(LOG_CRIT, "fdopen of socket for input", "");
  2537. X    if ((fo = fdopen(f, "w")) == NULL)
  2538. X        logit(LOG_CRIT, "fdopen of socket for output", "");
  2539. X
  2540. X    converse(fi, fo, fromaddr);
  2541. X    /* NOTREACHED */
  2542. X    return 0;
  2543. X}
  2544. X
  2545. X#ifndef NOBOMB
  2546. Xbomb(err)
  2547. Xint err;
  2548. X{
  2549. X    death(err);
  2550. X}
  2551. X#endif
  2552. X
  2553. Xlogit (sev, fmt, str)
  2554. Xint sev;
  2555. Xchar *fmt, *str;
  2556. X{
  2557. X#ifdef SYSLOG
  2558. X    (void) sprintf(logm, "%s: %s", progname, fmt);
  2559. X    (void) syslog(sev, logm, (str == "" && errno <= sys_nerr)?
  2560. X        sys_errlist[errno]: str);
  2561. X#else
  2562. X    (void) sprintf(logm, "%s: %s", progname, fmt);
  2563. X    (void) fprintf(stderr, logm, (str == "" && errno <= sys_nerr)?
  2564. X        sys_errlist[errno]: str);
  2565. X#endif
  2566. X}
  2567. SHAR_EOF
  2568. if test 5297 -ne "`wc -c < 'smtpd.c'`"
  2569. then
  2570.     echo shar: "error transmitting 'smtpd.c'" '(should have been 5297 characters)'
  2571. fi
  2572. fi
  2573. echo shar: "extracting 'sysexits.h'" '(3662 characters)'
  2574. if test -f 'sysexits.h'
  2575. then
  2576.     echo shar: "will not over-write existing file 'sysexits.h'"
  2577. else
  2578. sed 's/^X//' << \SHAR_EOF > 'sysexits.h'
  2579. X/*
  2580. X**  SYSEXITS.H -- Exit status codes for system programs.
  2581. X**
  2582. X**    This include file attempts to categorize possible error
  2583. X**    exit statuses for system programs, notably delivermail
  2584. X**    and the Berkeley network.
  2585. X**
  2586. X**    Error numbers begin at EX__BASE to reduce the possibility of
  2587. X**    clashing with other exit statuses that random programs may
  2588. X**    already return.  The meaning of the codes is approximately
  2589. X**    as follows:
  2590. X**
  2591. X**    EX_USAGE -- The command was used incorrectly, e.g., with
  2592. X**        the wrong number of arguments, a bad flag, a bad
  2593. X**        syntax in a parameter, or whatever.
  2594. X**    EX_DATAERR -- The input data was incorrect in some way.
  2595. X**        This should only be used for user's data & not
  2596. X**        system files.
  2597. X**    EX_NOINPUT -- An input file (not a system file) did not
  2598. X**        exist or was not readable.  This could also include
  2599. X**        errors like "No message" to a mailer (if it cared
  2600. X**        to catch it).
  2601. X**    EX_NOUSER -- The user specified did not exist.  This might
  2602. X**        be used for mail addresses or remote logins.
  2603. X**    EX_NOHOST -- The host specified did not exist.  This is used
  2604. X**        in mail addresses or network requests.
  2605. X**    EX_UNAVAILABLE -- A service is unavailable.  This can occur
  2606. X**        if a support program or file does not exist.  This
  2607. X**        can also be used as a catchall message when something
  2608. X**        you wanted to do doesn't work, but you don't know
  2609. X**        why.
  2610. X**    EX_SOFTWARE -- An internal software error has been detected.
  2611. X**        This should be limited to non-operating system related
  2612. X**        errors as possible.
  2613. X**    EX_OSERR -- An operating system error has been detected.
  2614. X**        This is intended to be used for such things as "cannot
  2615. X**        fork", "cannot create pipe", or the like.  It includes
  2616. X**        things like getuid returning a user that does not
  2617. X**        exist in the passwd file.
  2618. X**    EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
  2619. X**        etc.) does not exist, cannot be opened, or has some
  2620. X**        sort of error (e.g., syntax error).
  2621. X**    EX_CANTCREAT -- A (user specified) output file cannot be
  2622. X**        created.
  2623. X**    EX_IOERR -- An error occurred while doing I/O on some file.
  2624. X**    EX_TEMPFAIL -- temporary failure, indicating something that
  2625. X**        is not really an error.  In sendmail, this means
  2626. X**        that a mailer (e.g.) could not create a connection,
  2627. X**        and the request should be reattempted later.
  2628. X**    EX_PROTOCOL -- the remote system returned something that
  2629. X**        was "not possible" during a protocol exchange.
  2630. X**    EX_NOPERM -- You did not have sufficient permission to
  2631. X**        perform the operation.  This is not intended for
  2632. X**        file system problems, which should use NOINPUT or
  2633. X**        CANTCREAT, but rather for higher level permissions.
  2634. X**        For example, kre uses this to restrict who students
  2635. X**        can send mail to.
  2636. X**
  2637. X**    Maintained by Eric Allman (eric@berkeley, ucbvax!eric) --
  2638. X**        please mail changes to me.
  2639. X**
  2640. X**    @(#)sysexits.h    1.2    86/05/09    ACE (c)
  2641. X*/
  2642. X
  2643. X# define EX_OK        0    /* successful termination */
  2644. X
  2645. X# define EX__BASE    64    /* base value for error messages */
  2646. X
  2647. X# define EX_USAGE    64    /* command line usage error */
  2648. X# define EX_DATAERR    65    /* data format error */
  2649. X# define EX_NOINPUT    66    /* cannot open input */
  2650. X# define EX_NOUSER    67    /* addressee unknown */
  2651. X# define EX_NOHOST    68    /* host name unknown */
  2652. X# define EX_UNAVAILABLE    69    /* service unavailable */
  2653. X# define EX_SOFTWARE    70    /* internal software error */
  2654. X# define EX_OSERR    71    /* system error (e.g., can't fork) */
  2655. X# define EX_OSFILE    72    /* critical OS file missing */
  2656. X# define EX_CANTCREAT    73    /* can't create (user) output file */
  2657. X# define EX_IOERR    74    /* input/output error */
  2658. X# define EX_TEMPFAIL    75    /* temp failure; user is invited to retry */
  2659. X# define EX_PROTOCOL    76    /* remote error in protocol */
  2660. X# define EX_NOPERM    77    /* permission denied */
  2661. SHAR_EOF
  2662. if test 3662 -ne "`wc -c < 'sysexits.h'`"
  2663. then
  2664.     echo shar: "error transmitting 'sysexits.h'" '(should have been 3662 characters)'
  2665. fi
  2666. fi
  2667. echo shar: "extracting 'syslog.h'" '(24 characters)'
  2668. if test -f 'syslog.h'
  2669. then
  2670.     echo shar: "will not over-write existing file 'syslog.h'"
  2671. else
  2672. sed 's/^X//' << \SHAR_EOF > 'syslog.h'
  2673. X#include <sys/syslog.h>
  2674. SHAR_EOF
  2675. if test 24 -ne "`wc -c < 'syslog.h'`"
  2676. then
  2677.     echo shar: "error transmitting 'syslog.h'" '(should have been 24 characters)'
  2678. fi
  2679. fi
  2680. echo shar: "extracting 'MANIFEST'" '(144 characters)'
  2681. if test -f 'MANIFEST'
  2682. then
  2683.     echo shar: "will not over-write existing file 'MANIFEST'"
  2684. else
  2685. sed 's/^X//' << \SHAR_EOF > 'MANIFEST'
  2686. XMakefile
  2687. XREADME
  2688. Xcmds.h
  2689. Xconfig.h
  2690. Xconverse.c
  2691. Xdconverse.c
  2692. Xmisc.c
  2693. Xmiscerrs.h
  2694. Xmx.c
  2695. Xnetio.c
  2696. Xsmtp.8
  2697. Xsmtp.c
  2698. Xsmtp.h
  2699. Xsmtpd.c
  2700. Xsysexits.h
  2701. Xsyslog.h
  2702. XMANIFEST
  2703. SHAR_EOF
  2704. if test 144 -ne "`wc -c < 'MANIFEST'`"
  2705. then
  2706.     echo shar: "error transmitting 'MANIFEST'" '(should have been 144 characters)'
  2707. fi
  2708. fi
  2709. exit 0
  2710. #    End of shell archive
  2711.  
  2712. -- 
  2713. postmaster on node mhres (currently: Johan Vromans)
  2714.